Merge "Fix heap buffer overflow issue flagged by fuzzer test." into main
diff --git a/media/codec2/hal/common/Android.bp b/media/codec2/hal/common/Android.bp
new file mode 100644
index 0000000..e158cd2
--- /dev/null
+++ b/media/codec2/hal/common/Android.bp
@@ -0,0 +1,11 @@
+cc_library_headers {
+ name: "libcodec2_hal_common",
+ export_include_dirs: ["include/"],
+ vendor_available: true,
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media",
+ "com.android.media.swcodec",
+ ],
+ min_sdk_version: "29",
+}
diff --git a/media/codec2/hal/common/include/codec2/common/BufferTypes.h b/media/codec2/hal/common/include/codec2/common/BufferTypes.h
new file mode 100644
index 0000000..319ba62
--- /dev/null
+++ b/media/codec2/hal/common/include/codec2/common/BufferTypes.h
@@ -0,0 +1,1928 @@
+/*
+ * Copyright 2018 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-types"
+#include <android-base/logging.h>
+
+#include <codec2/hidl/1.0/types.h>
+#include <media/stagefright/foundation/AUtils.h>
+
+#include <C2AllocatorIon.h>
+#include <C2AllocatorGralloc.h>
+#include <C2BlockInternal.h>
+#include <C2Buffer.h>
+#include <C2Component.h>
+#include <C2FenceFactory.h>
+#include <C2Param.h>
+#include <C2ParamInternal.h>
+#include <C2PlatformSupport.h>
+#include <C2Work.h>
+#include <util/C2ParamUtils.h>
+
+#include <algorithm>
+#include <functional>
+#include <iomanip>
+#include <unordered_map>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using ::android::hardware::Return;
+using ::android::hardware::media::bufferpool::BufferPoolData;
+using ::android::hardware::media::bufferpool::V2_0::BufferStatusMessage;
+using ::android::hardware::media::bufferpool::V2_0::ResultStatus;
+using ::android::hardware::media::bufferpool::V2_0::implementation::
+ ClientManager;
+using ::android::hardware::media::bufferpool::V2_0::implementation::
+ TransactionId;
+
+const char* asString(Status status, const char* def) {
+ return asString(static_cast<c2_status_t>(status), def);
+}
+
+namespace /* unnamed */ {
+
+template <typename EnumClass>
+typename std::underlying_type<EnumClass>::type underlying_value(
+ EnumClass x) {
+ return static_cast<typename std::underlying_type<EnumClass>::type>(x);
+}
+
+template <typename Common, typename DstVector, typename SrcVector>
+void copyVector(DstVector* d, const SrcVector& s) {
+ static_assert(sizeof(Common) == sizeof(decltype((*d)[0])),
+ "DstVector's component size does not match Common");
+ static_assert(sizeof(Common) == sizeof(decltype(s[0])),
+ "SrcVector's component size does not match Common");
+ d->resize(s.size());
+ std::copy(
+ reinterpret_cast<const Common*>(&s[0]),
+ reinterpret_cast<const Common*>(&s[0] + s.size()),
+ reinterpret_cast<Common*>(&(*d)[0]));
+}
+
+// C2ParamField -> ParamField
+bool objcpy(ParamField *d, const C2ParamField &s) {
+ d->index = static_cast<ParamIndex>(_C2ParamInspector::GetIndex(s));
+ d->fieldId.offset = static_cast<uint32_t>(_C2ParamInspector::GetOffset(s));
+ d->fieldId.size = static_cast<uint32_t>(_C2ParamInspector::GetSize(s));
+ return true;
+}
+
+struct C2ParamFieldBuilder : public C2ParamField {
+ C2ParamFieldBuilder() : C2ParamField(
+ static_cast<C2Param::Index>(static_cast<uint32_t>(0)), 0, 0) {
+ }
+ // ParamField -> C2ParamField
+ C2ParamFieldBuilder(const ParamField& s) : C2ParamField(
+ static_cast<C2Param::Index>(static_cast<uint32_t>(s.index)),
+ static_cast<uint32_t>(s.fieldId.offset),
+ static_cast<uint32_t>(s.fieldId.size)) {
+ }
+};
+
+// C2WorkOrdinalStruct -> WorkOrdinal
+bool objcpy(WorkOrdinal *d, const C2WorkOrdinalStruct &s) {
+ d->frameIndex = static_cast<uint64_t>(s.frameIndex.peeku());
+ d->timestampUs = static_cast<uint64_t>(s.timestamp.peeku());
+ d->customOrdinal = static_cast<uint64_t>(s.customOrdinal.peeku());
+ return true;
+}
+
+// WorkOrdinal -> C2WorkOrdinalStruct
+bool objcpy(C2WorkOrdinalStruct *d, const WorkOrdinal &s) {
+ d->frameIndex = c2_cntr64_t(s.frameIndex);
+ d->timestamp = c2_cntr64_t(s.timestampUs);
+ d->customOrdinal = c2_cntr64_t(s.customOrdinal);
+ return true;
+}
+
+// C2FieldSupportedValues::range's type -> ValueRange
+bool objcpy(
+ ValueRange* d,
+ const decltype(C2FieldSupportedValues::range)& s) {
+ d->min = static_cast<PrimitiveValue>(s.min.u64);
+ d->max = static_cast<PrimitiveValue>(s.max.u64);
+ d->step = static_cast<PrimitiveValue>(s.step.u64);
+ d->num = static_cast<PrimitiveValue>(s.num.u64);
+ d->denom = static_cast<PrimitiveValue>(s.denom.u64);
+ return true;
+}
+
+// C2FieldSupportedValues -> FieldSupportedValues
+bool objcpy(FieldSupportedValues *d, const C2FieldSupportedValues &s) {
+ switch (s.type) {
+ case C2FieldSupportedValues::EMPTY: {
+ d->empty(::android::hidl::safe_union::V1_0::Monostate{});
+ break;
+ }
+ case C2FieldSupportedValues::RANGE: {
+ ValueRange range{};
+ if (!objcpy(&range, s.range)) {
+ LOG(ERROR) << "Invalid C2FieldSupportedValues::range.";
+ d->range(range);
+ return false;
+ }
+ d->range(range);
+ break;
+ }
+ case C2FieldSupportedValues::VALUES: {
+ hidl_vec<PrimitiveValue> values;
+ copyVector<uint64_t>(&values, s.values);
+ d->values(values);
+ break;
+ }
+ case C2FieldSupportedValues::FLAGS: {
+ hidl_vec<PrimitiveValue> flags;
+ copyVector<uint64_t>(&flags, s.values);
+ d->flags(flags);
+ break;
+ }
+ default:
+ LOG(DEBUG) << "Unrecognized C2FieldSupportedValues::type_t "
+ << "with underlying value " << underlying_value(s.type)
+ << ".";
+ return false;
+ }
+ return true;
+}
+
+// ValueRange -> C2FieldSupportedValues::range's type
+bool objcpy(
+ decltype(C2FieldSupportedValues::range)* d,
+ const ValueRange& s) {
+ d->min.u64 = static_cast<uint64_t>(s.min);
+ d->max.u64 = static_cast<uint64_t>(s.max);
+ d->step.u64 = static_cast<uint64_t>(s.step);
+ d->num.u64 = static_cast<uint64_t>(s.num);
+ d->denom.u64 = static_cast<uint64_t>(s.denom);
+ return true;
+}
+
+// FieldSupportedValues -> C2FieldSupportedValues
+bool objcpy(C2FieldSupportedValues *d, const FieldSupportedValues &s) {
+ switch (s.getDiscriminator()) {
+ case FieldSupportedValues::hidl_discriminator::empty: {
+ d->type = C2FieldSupportedValues::EMPTY;
+ break;
+ }
+ case FieldSupportedValues::hidl_discriminator::range: {
+ d->type = C2FieldSupportedValues::RANGE;
+ if (!objcpy(&d->range, s.range())) {
+ LOG(ERROR) << "Invalid FieldSupportedValues::range.";
+ return false;
+ }
+ d->values.resize(0);
+ break;
+ }
+ case FieldSupportedValues::hidl_discriminator::values: {
+ d->type = C2FieldSupportedValues::VALUES;
+ copyVector<uint64_t>(&d->values, s.values());
+ break;
+ }
+ case FieldSupportedValues::hidl_discriminator::flags: {
+ d->type = C2FieldSupportedValues::FLAGS;
+ copyVector<uint64_t>(&d->values, s.flags());
+ break;
+ }
+ default:
+ LOG(WARNING) << "Unrecognized FieldSupportedValues::getDiscriminator()";
+ return false;
+ }
+ return true;
+}
+
+} // unnamed namespace
+
+// C2FieldSupportedValuesQuery -> FieldSupportedValuesQuery
+bool objcpy(
+ FieldSupportedValuesQuery* d,
+ const C2FieldSupportedValuesQuery& s) {
+ if (!objcpy(&d->field, s.field())) {
+ LOG(ERROR) << "Invalid C2FieldSupportedValuesQuery::field.";
+ return false;
+ }
+ switch (s.type()) {
+ case C2FieldSupportedValuesQuery::POSSIBLE:
+ d->type = FieldSupportedValuesQuery::Type::POSSIBLE;
+ break;
+ case C2FieldSupportedValuesQuery::CURRENT:
+ d->type = FieldSupportedValuesQuery::Type::CURRENT;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized C2FieldSupportedValuesQuery::type_t "
+ << "with underlying value " << underlying_value(s.type())
+ << ".";
+ d->type = static_cast<FieldSupportedValuesQuery::Type>(s.type());
+ }
+ return true;
+}
+
+// FieldSupportedValuesQuery -> C2FieldSupportedValuesQuery
+bool objcpy(
+ C2FieldSupportedValuesQuery* d,
+ const FieldSupportedValuesQuery& s) {
+ C2FieldSupportedValuesQuery::type_t dType;
+ switch (s.type) {
+ case FieldSupportedValuesQuery::Type::POSSIBLE:
+ dType = C2FieldSupportedValuesQuery::POSSIBLE;
+ break;
+ case FieldSupportedValuesQuery::Type::CURRENT:
+ dType = C2FieldSupportedValuesQuery::CURRENT;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized FieldSupportedValuesQuery::Type "
+ << "with underlying value " << underlying_value(s.type)
+ << ".";
+ dType = static_cast<C2FieldSupportedValuesQuery::type_t>(s.type);
+ }
+ *d = C2FieldSupportedValuesQuery(C2ParamFieldBuilder(s.field), dType);
+ return true;
+}
+
+// C2FieldSupportedValuesQuery -> FieldSupportedValuesQueryResult
+bool objcpy(
+ FieldSupportedValuesQueryResult* d,
+ const C2FieldSupportedValuesQuery& s) {
+ d->status = static_cast<Status>(s.status);
+ return objcpy(&d->values, s.values);
+}
+
+// FieldSupportedValuesQuery, FieldSupportedValuesQueryResult ->
+// C2FieldSupportedValuesQuery
+bool objcpy(
+ C2FieldSupportedValuesQuery* d,
+ const FieldSupportedValuesQuery& sq,
+ const FieldSupportedValuesQueryResult& sr) {
+ if (!objcpy(d, sq)) {
+ LOG(ERROR) << "Invalid FieldSupportedValuesQuery.";
+ return false;
+ }
+ d->status = static_cast<c2_status_t>(sr.status);
+ if (!objcpy(&d->values, sr.values)) {
+ LOG(ERROR) << "Invalid FieldSupportedValuesQueryResult::values.";
+ return false;
+ }
+ return true;
+}
+
+// C2Component::Traits -> IComponentStore::ComponentTraits
+bool objcpy(
+ IComponentStore::ComponentTraits *d,
+ const C2Component::Traits &s) {
+ d->name = s.name;
+
+ switch (s.domain) {
+ case C2Component::DOMAIN_VIDEO:
+ d->domain = IComponentStore::ComponentTraits::Domain::VIDEO;
+ break;
+ case C2Component::DOMAIN_AUDIO:
+ d->domain = IComponentStore::ComponentTraits::Domain::AUDIO;
+ break;
+ case C2Component::DOMAIN_IMAGE:
+ d->domain = IComponentStore::ComponentTraits::Domain::IMAGE;
+ break;
+ case C2Component::DOMAIN_OTHER:
+ d->domain = IComponentStore::ComponentTraits::Domain::OTHER;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized C2Component::domain_t "
+ << "with underlying value " << underlying_value(s.domain)
+ << ".";
+ d->domain = static_cast<IComponentStore::ComponentTraits::Domain>(
+ s.domain);
+ }
+
+ switch (s.kind) {
+ case C2Component::KIND_DECODER:
+ d->kind = IComponentStore::ComponentTraits::Kind::DECODER;
+ break;
+ case C2Component::KIND_ENCODER:
+ d->kind = IComponentStore::ComponentTraits::Kind::ENCODER;
+ break;
+ case C2Component::KIND_OTHER:
+ d->kind = IComponentStore::ComponentTraits::Kind::OTHER;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized C2Component::kind_t "
+ << "with underlying value " << underlying_value(s.kind)
+ << ".";
+ d->kind = static_cast<IComponentStore::ComponentTraits::Kind>(
+ s.kind);
+ }
+
+ d->rank = static_cast<uint32_t>(s.rank);
+
+ d->mediaType = s.mediaType;
+
+ d->aliases.resize(s.aliases.size());
+ for (size_t ix = s.aliases.size(); ix > 0; ) {
+ --ix;
+ d->aliases[ix] = s.aliases[ix];
+ }
+ return true;
+}
+
+// ComponentTraits -> C2Component::Traits, std::unique_ptr<std::vector<std::string>>
+bool objcpy(
+ C2Component::Traits* d,
+ const IComponentStore::ComponentTraits& s) {
+ d->name = s.name.c_str();
+
+ switch (s.domain) {
+ case IComponentStore::ComponentTraits::Domain::VIDEO:
+ d->domain = C2Component::DOMAIN_VIDEO;
+ break;
+ case IComponentStore::ComponentTraits::Domain::AUDIO:
+ d->domain = C2Component::DOMAIN_AUDIO;
+ break;
+ case IComponentStore::ComponentTraits::Domain::IMAGE:
+ d->domain = C2Component::DOMAIN_IMAGE;
+ break;
+ case IComponentStore::ComponentTraits::Domain::OTHER:
+ d->domain = C2Component::DOMAIN_OTHER;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized ComponentTraits::Domain "
+ << "with underlying value " << underlying_value(s.domain)
+ << ".";
+ d->domain = static_cast<C2Component::domain_t>(s.domain);
+ }
+
+ switch (s.kind) {
+ case IComponentStore::ComponentTraits::Kind::DECODER:
+ d->kind = C2Component::KIND_DECODER;
+ break;
+ case IComponentStore::ComponentTraits::Kind::ENCODER:
+ d->kind = C2Component::KIND_ENCODER;
+ break;
+ case IComponentStore::ComponentTraits::Kind::OTHER:
+ d->kind = C2Component::KIND_OTHER;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized ComponentTraits::Kind "
+ << "with underlying value " << underlying_value(s.kind)
+ << ".";
+ d->kind = static_cast<C2Component::kind_t>(s.kind);
+ }
+
+ d->rank = static_cast<C2Component::rank_t>(s.rank);
+ d->mediaType = s.mediaType.c_str();
+ d->aliases.resize(s.aliases.size());
+ for (size_t i = 0; i < s.aliases.size(); ++i) {
+ d->aliases[i] = s.aliases[i];
+ }
+ return true;
+}
+
+namespace /* unnamed */ {
+
+// C2ParamFieldValues -> ParamFieldValues
+bool objcpy(ParamFieldValues *d, const C2ParamFieldValues &s) {
+ if (!objcpy(&d->paramOrField, s.paramOrField)) {
+ LOG(ERROR) << "Invalid C2ParamFieldValues::paramOrField.";
+ return false;
+ }
+ if (s.values) {
+ d->values.resize(1);
+ if (!objcpy(&d->values[0], *s.values)) {
+ LOG(ERROR) << "Invalid C2ParamFieldValues::values.";
+ return false;
+ }
+ return true;
+ }
+ d->values.resize(0);
+ return true;
+}
+
+// ParamFieldValues -> C2ParamFieldValues
+bool objcpy(C2ParamFieldValues *d, const ParamFieldValues &s) {
+ d->paramOrField = C2ParamFieldBuilder(s.paramOrField);
+ if (s.values.size() == 1) {
+ d->values = std::make_unique<C2FieldSupportedValues>();
+ if (!objcpy(d->values.get(), s.values[0])) {
+ LOG(ERROR) << "Invalid ParamFieldValues::values.";
+ return false;
+ }
+ return true;
+ } else if (s.values.size() == 0) {
+ d->values.reset();
+ return true;
+ }
+ LOG(ERROR) << "Invalid ParamFieldValues: "
+ "Two or more FieldSupportedValues objects exist in "
+ "ParamFieldValues. "
+ "Only zero or one is allowed.";
+ return false;
+}
+
+} // unnamed namespace
+
+// C2SettingResult -> SettingResult
+bool objcpy(SettingResult *d, const C2SettingResult &s) {
+ switch (s.failure) {
+ case C2SettingResult::BAD_TYPE:
+ d->failure = SettingResult::Failure::BAD_TYPE;
+ break;
+ case C2SettingResult::BAD_PORT:
+ d->failure = SettingResult::Failure::BAD_PORT;
+ break;
+ case C2SettingResult::BAD_INDEX:
+ d->failure = SettingResult::Failure::BAD_INDEX;
+ break;
+ case C2SettingResult::READ_ONLY:
+ d->failure = SettingResult::Failure::READ_ONLY;
+ break;
+ case C2SettingResult::MISMATCH:
+ d->failure = SettingResult::Failure::MISMATCH;
+ break;
+ case C2SettingResult::BAD_VALUE:
+ d->failure = SettingResult::Failure::BAD_VALUE;
+ break;
+ case C2SettingResult::CONFLICT:
+ d->failure = SettingResult::Failure::CONFLICT;
+ break;
+ case C2SettingResult::UNSUPPORTED:
+ d->failure = SettingResult::Failure::UNSUPPORTED;
+ break;
+ case C2SettingResult::INFO_BAD_VALUE:
+ d->failure = SettingResult::Failure::INFO_BAD_VALUE;
+ break;
+ case C2SettingResult::INFO_CONFLICT:
+ d->failure = SettingResult::Failure::INFO_CONFLICT;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized C2SettingResult::Failure "
+ << "with underlying value " << underlying_value(s.failure)
+ << ".";
+ d->failure = static_cast<SettingResult::Failure>(s.failure);
+ }
+ if (!objcpy(&d->field, s.field)) {
+ LOG(ERROR) << "Invalid C2SettingResult::field.";
+ return false;
+ }
+ d->conflicts.resize(s.conflicts.size());
+ size_t i = 0;
+ for (const C2ParamFieldValues& sConflict : s.conflicts) {
+ ParamFieldValues &dConflict = d->conflicts[i++];
+ if (!objcpy(&dConflict, sConflict)) {
+ LOG(ERROR) << "Invalid C2SettingResult::conflicts["
+ << i - 1 << "].";
+ return false;
+ }
+ }
+ return true;
+}
+
+// SettingResult -> std::unique_ptr<C2SettingResult>
+bool objcpy(std::unique_ptr<C2SettingResult> *d, const SettingResult &s) {
+ *d = std::unique_ptr<C2SettingResult>(new C2SettingResult {
+ .field = C2ParamFieldValues(C2ParamFieldBuilder()) });
+ if (!*d) {
+ LOG(ERROR) << "No memory for C2SettingResult.";
+ return false;
+ }
+
+ // failure
+ switch (s.failure) {
+ case SettingResult::Failure::BAD_TYPE:
+ (*d)->failure = C2SettingResult::BAD_TYPE;
+ break;
+ case SettingResult::Failure::BAD_PORT:
+ (*d)->failure = C2SettingResult::BAD_PORT;
+ break;
+ case SettingResult::Failure::BAD_INDEX:
+ (*d)->failure = C2SettingResult::BAD_INDEX;
+ break;
+ case SettingResult::Failure::READ_ONLY:
+ (*d)->failure = C2SettingResult::READ_ONLY;
+ break;
+ case SettingResult::Failure::MISMATCH:
+ (*d)->failure = C2SettingResult::MISMATCH;
+ break;
+ case SettingResult::Failure::BAD_VALUE:
+ (*d)->failure = C2SettingResult::BAD_VALUE;
+ break;
+ case SettingResult::Failure::CONFLICT:
+ (*d)->failure = C2SettingResult::CONFLICT;
+ break;
+ case SettingResult::Failure::UNSUPPORTED:
+ (*d)->failure = C2SettingResult::UNSUPPORTED;
+ break;
+ case SettingResult::Failure::INFO_BAD_VALUE:
+ (*d)->failure = C2SettingResult::INFO_BAD_VALUE;
+ break;
+ case SettingResult::Failure::INFO_CONFLICT:
+ (*d)->failure = C2SettingResult::INFO_CONFLICT;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized SettingResult::Failure "
+ << "with underlying value " << underlying_value(s.failure)
+ << ".";
+ (*d)->failure = static_cast<C2SettingResult::Failure>(s.failure);
+ }
+
+ // field
+ if (!objcpy(&(*d)->field, s.field)) {
+ LOG(ERROR) << "Invalid SettingResult::field.";
+ return false;
+ }
+
+ // conflicts
+ (*d)->conflicts.clear();
+ (*d)->conflicts.reserve(s.conflicts.size());
+ for (const ParamFieldValues& sConflict : s.conflicts) {
+ (*d)->conflicts.emplace_back(
+ C2ParamFieldValues{ C2ParamFieldBuilder(), nullptr });
+ if (!objcpy(&(*d)->conflicts.back(), sConflict)) {
+ LOG(ERROR) << "Invalid SettingResult::conflicts.";
+ return false;
+ }
+ }
+ return true;
+}
+
+// C2ParamDescriptor -> ParamDescriptor
+bool objcpy(ParamDescriptor *d, const C2ParamDescriptor &s) {
+ d->index = static_cast<ParamIndex>(s.index());
+ d->attrib = static_cast<hidl_bitfield<ParamDescriptor::Attrib>>(
+ _C2ParamInspector::GetAttrib(s));
+ d->name = s.name();
+ copyVector<uint32_t>(&d->dependencies, s.dependencies());
+ return true;
+}
+
+// ParamDescriptor -> C2ParamDescriptor
+bool objcpy(std::shared_ptr<C2ParamDescriptor> *d, const ParamDescriptor &s) {
+ std::vector<C2Param::Index> dDependencies;
+ dDependencies.reserve(s.dependencies.size());
+ for (const ParamIndex& sDependency : s.dependencies) {
+ dDependencies.emplace_back(static_cast<uint32_t>(sDependency));
+ }
+ *d = std::make_shared<C2ParamDescriptor>(
+ C2Param::Index(static_cast<uint32_t>(s.index)),
+ static_cast<C2ParamDescriptor::attrib_t>(s.attrib),
+ C2String(s.name.c_str()),
+ std::move(dDependencies));
+ return true;
+}
+
+// C2StructDescriptor -> StructDescriptor
+bool objcpy(StructDescriptor *d, const C2StructDescriptor &s) {
+ d->type = static_cast<ParamIndex>(s.coreIndex().coreIndex());
+ d->fields.resize(s.numFields());
+ size_t i = 0;
+ for (const auto& sField : s) {
+ FieldDescriptor& dField = d->fields[i++];
+ dField.fieldId.offset = static_cast<uint32_t>(
+ _C2ParamInspector::GetOffset(sField));
+ dField.fieldId.size = static_cast<uint32_t>(
+ _C2ParamInspector::GetSize(sField));
+ dField.type = static_cast<hidl_bitfield<FieldDescriptor::Type>>(
+ sField.type());
+ dField.extent = static_cast<uint32_t>(sField.extent());
+ dField.name = static_cast<hidl_string>(sField.name());
+ const auto& sNamedValues = sField.namedValues();
+ dField.namedValues.resize(sNamedValues.size());
+ size_t j = 0;
+ for (const auto& sNamedValue : sNamedValues) {
+ FieldDescriptor::NamedValue& dNamedValue = dField.namedValues[j++];
+ dNamedValue.name = static_cast<hidl_string>(sNamedValue.first);
+ dNamedValue.value = static_cast<PrimitiveValue>(
+ sNamedValue.second.u64);
+ }
+ }
+ return true;
+}
+
+// StructDescriptor -> C2StructDescriptor
+bool objcpy(std::unique_ptr<C2StructDescriptor> *d, const StructDescriptor &s) {
+ C2Param::CoreIndex dIndex = C2Param::CoreIndex(static_cast<uint32_t>(s.type));
+ std::vector<C2FieldDescriptor> dFields;
+ dFields.reserve(s.fields.size());
+ for (const auto &sField : s.fields) {
+ C2FieldDescriptor dField = {
+ static_cast<uint32_t>(sField.type),
+ sField.extent,
+ sField.name,
+ sField.fieldId.offset,
+ sField.fieldId.size };
+ C2FieldDescriptor::NamedValuesType namedValues;
+ namedValues.reserve(sField.namedValues.size());
+ for (const auto& sNamedValue : sField.namedValues) {
+ namedValues.emplace_back(
+ sNamedValue.name,
+ C2Value::Primitive(static_cast<uint64_t>(sNamedValue.value)));
+ }
+ _C2ParamInspector::AddNamedValues(dField, std::move(namedValues));
+ dFields.emplace_back(dField);
+ }
+ *d = std::make_unique<C2StructDescriptor>(
+ _C2ParamInspector::CreateStructDescriptor(dIndex, std::move(dFields)));
+ return true;
+}
+
+namespace /* unnamed */ {
+
+// Find or add a hidl BaseBlock object from a given C2Handle* to a list and an
+// associated map.
+// Note: The handle is not cloned.
+bool _addBaseBlock(
+ uint32_t* index,
+ const C2Handle* handle,
+ std::list<BaseBlock>* baseBlocks,
+ std::map<const void*, uint32_t>* baseBlockIndices) {
+ if (!handle) {
+ LOG(ERROR) << "addBaseBlock called on a null C2Handle.";
+ return false;
+ }
+ auto it = baseBlockIndices->find(handle);
+ if (it != baseBlockIndices->end()) {
+ *index = it->second;
+ } else {
+ *index = baseBlocks->size();
+ baseBlockIndices->emplace(handle, *index);
+ baseBlocks->emplace_back();
+
+ BaseBlock &dBaseBlock = baseBlocks->back();
+ // This does not clone the handle.
+ dBaseBlock.nativeBlock(
+ reinterpret_cast<const native_handle_t*>(handle));
+
+ }
+ return true;
+}
+
+// Find or add a hidl BaseBlock object from a given BufferPoolData to a list and
+// an associated map.
+bool _addBaseBlock(
+ uint32_t* index,
+ const std::shared_ptr<BufferPoolData> bpData,
+ BufferPoolSender* bufferPoolSender,
+ std::list<BaseBlock>* baseBlocks,
+ std::map<const void*, uint32_t>* baseBlockIndices) {
+ if (!bpData) {
+ LOG(ERROR) << "addBaseBlock called on a null BufferPoolData.";
+ return false;
+ }
+ auto it = baseBlockIndices->find(bpData.get());
+ if (it != baseBlockIndices->end()) {
+ *index = it->second;
+ } else {
+ *index = baseBlocks->size();
+ baseBlockIndices->emplace(bpData.get(), *index);
+ baseBlocks->emplace_back();
+
+ BaseBlock &dBaseBlock = baseBlocks->back();
+
+ if (bufferPoolSender) {
+ BufferStatusMessage pooledBlock;
+ ResultStatus bpStatus = bufferPoolSender->send(
+ bpData,
+ &pooledBlock);
+
+ if (bpStatus != ResultStatus::OK) {
+ LOG(ERROR) << "Failed to send buffer with BufferPool. Error: "
+ << static_cast<int32_t>(bpStatus)
+ << ".";
+ return false;
+ }
+ dBaseBlock.pooledBlock(pooledBlock);
+ }
+ }
+ return true;
+}
+
+bool addBaseBlock(
+ uint32_t* index,
+ const C2Handle* handle,
+ const std::shared_ptr<const _C2BlockPoolData>& blockPoolData,
+ BufferPoolSender* bufferPoolSender,
+ std::list<BaseBlock>* baseBlocks,
+ std::map<const void*, uint32_t>* baseBlockIndices) {
+ if (!blockPoolData) {
+ // No BufferPoolData ==> NATIVE block.
+ return _addBaseBlock(
+ index, handle,
+ baseBlocks, baseBlockIndices);
+ }
+ switch (blockPoolData->getType()) {
+ case _C2BlockPoolData::TYPE_BUFFERPOOL: {
+ // BufferPoolData
+ std::shared_ptr<BufferPoolData> bpData;
+ if (!_C2BlockFactory::GetBufferPoolData(blockPoolData, &bpData)
+ || !bpData) {
+ LOG(ERROR) << "BufferPoolData unavailable in a block.";
+ return false;
+ }
+ return _addBaseBlock(
+ index, bpData,
+ bufferPoolSender, baseBlocks, baseBlockIndices);
+ }
+ case _C2BlockPoolData::TYPE_BUFFERQUEUE:
+ uint32_t gen;
+ uint64_t bqId;
+ int32_t bqSlot;
+ // Update handle if migration happened.
+ if (_C2BlockFactory::GetBufferQueueData(
+ blockPoolData, &gen, &bqId, &bqSlot)) {
+ android::MigrateNativeCodec2GrallocHandle(
+ const_cast<native_handle_t*>(handle), gen, bqId, bqSlot);
+ }
+ return _addBaseBlock(
+ index, handle,
+ baseBlocks, baseBlockIndices);
+ default:
+ LOG(ERROR) << "Unknown C2BlockPoolData type.";
+ return false;
+ }
+}
+
+// C2Fence -> hidl_handle
+// Note: File descriptors are not duplicated. The original file descriptor must
+// not be closed before the transaction is complete.
+bool objcpy(hidl_handle* d, const C2Fence& s) {
+ d->setTo(nullptr);
+ native_handle_t* handle = _C2FenceFactory::CreateNativeHandle(s);
+ if (handle) {
+ d->setTo(handle, true /* owns */);
+// } else if (!s.ready()) {
+// // TODO: we should wait for unmarshallable fences but this may not be
+// // the best place for it. We can safely ignore here as at this time
+// // all fences used here are marshallable.
+ }
+ return true;
+}
+
+// C2ConstLinearBlock -> Block
+// Note: Native handles are not duplicated. The original handles must not be
+// closed before the transaction is complete.
+bool objcpy(Block* d, const C2ConstLinearBlock& s,
+ BufferPoolSender* bufferPoolSender,
+ std::list<BaseBlock>* baseBlocks,
+ std::map<const void*, uint32_t>* baseBlockIndices) {
+ std::shared_ptr<const _C2BlockPoolData> bpData =
+ _C2BlockFactory::GetLinearBlockPoolData(s);
+ if (!addBaseBlock(&d->index, s.handle(), bpData,
+ bufferPoolSender, baseBlocks, baseBlockIndices)) {
+ LOG(ERROR) << "Invalid block data in C2ConstLinearBlock.";
+ return false;
+ }
+
+ // Create the metadata.
+ C2Hidl_RangeInfo dRangeInfo;
+ dRangeInfo.offset = static_cast<uint32_t>(s.offset());
+ dRangeInfo.length = static_cast<uint32_t>(s.size());
+ if (!createParamsBlob(&d->meta, std::vector<C2Param*>{ &dRangeInfo })) {
+ LOG(ERROR) << "Invalid range info in C2ConstLinearBlock.";
+ return false;
+ }
+
+ // Copy the fence
+ if (!objcpy(&d->fence, s.fence())) {
+ LOG(ERROR) << "Invalid C2ConstLinearBlock::fence.";
+ return false;
+ }
+ return true;
+}
+
+// C2ConstGraphicBlock -> Block
+// Note: Native handles are not duplicated. The original handles must not be
+// closed before the transaction is complete.
+bool objcpy(Block* d, const C2ConstGraphicBlock& s,
+ BufferPoolSender* bufferPoolSender,
+ std::list<BaseBlock>* baseBlocks,
+ std::map<const void*, uint32_t>* baseBlockIndices) {
+ std::shared_ptr<const _C2BlockPoolData> bpData =
+ _C2BlockFactory::GetGraphicBlockPoolData(s);
+ if (!addBaseBlock(&d->index, s.handle(), bpData,
+ bufferPoolSender, baseBlocks, baseBlockIndices)) {
+ LOG(ERROR) << "Invalid block data in C2ConstGraphicBlock.";
+ return false;
+ }
+
+ // Create the metadata.
+ C2Hidl_RectInfo dRectInfo;
+ C2Rect sRect = s.crop();
+ dRectInfo.left = static_cast<uint32_t>(sRect.left);
+ dRectInfo.top = static_cast<uint32_t>(sRect.top);
+ dRectInfo.width = static_cast<uint32_t>(sRect.width);
+ dRectInfo.height = static_cast<uint32_t>(sRect.height);
+ if (!createParamsBlob(&d->meta, std::vector<C2Param*>{ &dRectInfo })) {
+ LOG(ERROR) << "Invalid rect info in C2ConstGraphicBlock.";
+ return false;
+ }
+
+ // Copy the fence
+ if (!objcpy(&d->fence, s.fence())) {
+ LOG(ERROR) << "Invalid C2ConstGraphicBlock::fence.";
+ return false;
+ }
+ return true;
+}
+
+// C2BufferData -> Buffer
+// This function only fills in d->blocks.
+bool objcpy(Buffer* d, const C2BufferData& s,
+ BufferPoolSender* bufferPoolSender,
+ std::list<BaseBlock>* baseBlocks,
+ std::map<const void*, uint32_t>* baseBlockIndices) {
+ d->blocks.resize(
+ s.linearBlocks().size() +
+ s.graphicBlocks().size());
+ size_t i = 0;
+ for (const C2ConstLinearBlock& linearBlock : s.linearBlocks()) {
+ Block& dBlock = d->blocks[i++];
+ if (!objcpy(
+ &dBlock, linearBlock,
+ bufferPoolSender, baseBlocks, baseBlockIndices)) {
+ LOG(ERROR) << "Invalid C2BufferData::linearBlocks. "
+ << "(Destination index = " << i - 1 << ".)";
+ return false;
+ }
+ }
+ for (const C2ConstGraphicBlock& graphicBlock : s.graphicBlocks()) {
+ Block& dBlock = d->blocks[i++];
+ if (!objcpy(
+ &dBlock, graphicBlock,
+ bufferPoolSender, baseBlocks, baseBlockIndices)) {
+ LOG(ERROR) << "Invalid C2BufferData::graphicBlocks. "
+ << "(Destination index = " << i - 1 << ".)";
+ return false;
+ }
+ }
+ return true;
+}
+
+// C2Buffer -> Buffer
+bool objcpy(Buffer* d, const C2Buffer& s,
+ BufferPoolSender* bufferPoolSender,
+ std::list<BaseBlock>* baseBlocks,
+ std::map<const void*, uint32_t>* baseBlockIndices) {
+ if (!createParamsBlob(&d->info, s.info())) {
+ LOG(ERROR) << "Invalid C2Buffer::info.";
+ return false;
+ }
+ if (!objcpy(d, s.data(), bufferPoolSender, baseBlocks, baseBlockIndices)) {
+ LOG(ERROR) << "Invalid C2Buffer::data.";
+ return false;
+ }
+ return true;
+}
+
+// C2InfoBuffer -> InfoBuffer
+bool objcpy(InfoBuffer* d, const C2InfoBuffer& s,
+ BufferPoolSender* bufferPoolSender,
+ std::list<BaseBlock>* baseBlocks,
+ std::map<const void*, uint32_t>* baseBlockIndices) {
+ d->index = static_cast<ParamIndex>(s.index());
+ Buffer& dBuffer = d->buffer;
+ if (!objcpy(&dBuffer, s.data(), bufferPoolSender, baseBlocks, baseBlockIndices)) {
+ LOG(ERROR) << "Invalid C2InfoBuffer::data";
+ return false;
+ }
+ return true;
+}
+
+// C2FrameData -> FrameData
+bool objcpy(FrameData* d, const C2FrameData& s,
+ BufferPoolSender* bufferPoolSender,
+ std::list<BaseBlock>* baseBlocks,
+ std::map<const void*, uint32_t>* baseBlockIndices) {
+ d->flags = static_cast<hidl_bitfield<FrameData::Flags>>(s.flags);
+ if (!objcpy(&d->ordinal, s.ordinal)) {
+ LOG(ERROR) << "Invalid C2FrameData::ordinal.";
+ return false;
+ }
+
+ d->buffers.resize(s.buffers.size());
+ size_t i = 0;
+ for (const std::shared_ptr<C2Buffer>& sBuffer : s.buffers) {
+ Buffer& dBuffer = d->buffers[i++];
+ if (!sBuffer) {
+ // A null (pointer to) C2Buffer corresponds to a Buffer with empty
+ // info and blocks.
+ dBuffer.info.resize(0);
+ dBuffer.blocks.resize(0);
+ continue;
+ }
+ if (!objcpy(
+ &dBuffer, *sBuffer,
+ bufferPoolSender, baseBlocks, baseBlockIndices)) {
+ LOG(ERROR) << "Invalid C2FrameData::buffers["
+ << i - 1 << "].";
+ return false;
+ }
+ }
+
+ if (!createParamsBlob(&d->configUpdate, s.configUpdate)) {
+ LOG(ERROR) << "Invalid C2FrameData::configUpdate.";
+ return false;
+ }
+
+ d->infoBuffers.resize(s.infoBuffers.size());
+ i = 0;
+ for (const C2InfoBuffer& sInfoBuffer : s.infoBuffers) {
+ InfoBuffer& dInfoBuffer = d->infoBuffers[i++];
+ if (!objcpy(&dInfoBuffer, sInfoBuffer,
+ bufferPoolSender, baseBlocks, baseBlockIndices)) {
+ LOG(ERROR) << "Invalid C2FrameData::infoBuffers["
+ << i - 1 << "].";
+ return false;
+ }
+ }
+
+ return true;
+}
+
+} // unnamed namespace
+
+// DefaultBufferPoolSender's implementation
+
+DefaultBufferPoolSender::DefaultBufferPoolSender(
+ const sp<IClientManager>& receiverManager,
+ std::chrono::steady_clock::duration refreshInterval)
+ : mReceiverManager(receiverManager),
+ mRefreshInterval(refreshInterval) {
+}
+
+void DefaultBufferPoolSender::setReceiver(
+ const sp<IClientManager>& receiverManager,
+ std::chrono::steady_clock::duration refreshInterval) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mReceiverManager != receiverManager) {
+ mReceiverManager = receiverManager;
+ mConnections.clear();
+ }
+ mRefreshInterval = refreshInterval;
+}
+
+ResultStatus DefaultBufferPoolSender::send(
+ const std::shared_ptr<BufferPoolData>& bpData,
+ BufferStatusMessage* bpMessage) {
+ int64_t connectionId = bpData->mConnectionId;
+ if (connectionId == 0) {
+ LOG(WARNING) << "registerSender -- invalid sender connection id (0).";
+ return ResultStatus::CRITICAL_ERROR;
+ }
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (!mReceiverManager) {
+ LOG(ERROR) << "No access to receiver's BufferPool.";
+ return ResultStatus::NOT_FOUND;
+ }
+ if (!mSenderManager) {
+ mSenderManager = ClientManager::getInstance();
+ if (!mSenderManager) {
+ LOG(ERROR) << "Failed to retrieve local BufferPool ClientManager.";
+ return ResultStatus::CRITICAL_ERROR;
+ }
+ }
+
+ int64_t receiverConnectionId{0};
+ auto foundConnection = mConnections.find(connectionId);
+ bool isNewConnection = foundConnection == mConnections.end();
+ std::chrono::steady_clock::time_point now =
+ std::chrono::steady_clock::now();
+ if (isNewConnection ||
+ (now - foundConnection->second.lastSent > mRefreshInterval)) {
+ // Initialize the bufferpool connection.
+ ResultStatus rs =
+ mSenderManager->registerSender(mReceiverManager,
+ connectionId,
+ &receiverConnectionId);
+ if ((rs != ResultStatus::OK) && (rs != ResultStatus::ALREADY_EXISTS)) {
+ LOG(WARNING) << "registerSender -- returned error: "
+ << static_cast<int32_t>(rs)
+ << ".";
+ return rs;
+ } else if (receiverConnectionId == 0) {
+ LOG(WARNING) << "registerSender -- "
+ "invalid receiver connection id (0).";
+ return ResultStatus::CRITICAL_ERROR;
+ } else {
+ if (isNewConnection) {
+ foundConnection = mConnections.try_emplace(
+ connectionId, receiverConnectionId, now).first;
+ } else {
+ foundConnection->second.receiverConnectionId = receiverConnectionId;
+ }
+ }
+ } else {
+ receiverConnectionId = foundConnection->second.receiverConnectionId;
+ }
+
+ uint64_t transactionId;
+ int64_t timestampUs;
+ ResultStatus rs = mSenderManager->postSend(
+ receiverConnectionId, bpData, &transactionId, ×tampUs);
+ if (rs != ResultStatus::OK) {
+ LOG(ERROR) << "ClientManager::postSend -- returned error: "
+ << static_cast<int32_t>(rs)
+ << ".";
+ mConnections.erase(foundConnection);
+ return rs;
+ }
+ if (!bpMessage) {
+ LOG(ERROR) << "Null output parameter for BufferStatusMessage.";
+ mConnections.erase(foundConnection);
+ return ResultStatus::CRITICAL_ERROR;
+ }
+ bpMessage->connectionId = receiverConnectionId;
+ bpMessage->bufferId = bpData->mId;
+ bpMessage->transactionId = transactionId;
+ bpMessage->timestampUs = timestampUs;
+ foundConnection->second.lastSent = now;
+ return rs;
+}
+
+// std::list<std::unique_ptr<C2Work>> -> WorkBundle
+bool objcpy(
+ WorkBundle* d,
+ const std::list<std::unique_ptr<C2Work>>& s,
+ BufferPoolSender* bufferPoolSender) {
+ // baseBlocks holds a list of BaseBlock objects that Blocks can refer to.
+ std::list<BaseBlock> baseBlocks;
+
+ // baseBlockIndices maps a raw pointer to native_handle_t or BufferPoolData
+ // inside baseBlocks to the corresponding index into baseBlocks. The keys
+ // (pointers) are used to identify blocks that have the same "base block" in
+ // s, a list of C2Work objects. Because baseBlocks will be copied into a
+ // hidl_vec eventually, the values of baseBlockIndices are zero-based
+ // integer indices instead of list iterators.
+ //
+ // Note that the pointers can be raw because baseBlockIndices has a shorter
+ // lifespan than all of base blocks.
+ std::map<const void*, uint32_t> baseBlockIndices;
+
+ d->works.resize(s.size());
+ size_t i = 0;
+ for (const std::unique_ptr<C2Work>& sWork : s) {
+ Work &dWork = d->works[i++];
+ if (!sWork) {
+ LOG(WARNING) << "Null C2Work encountered.";
+ continue;
+ }
+
+ // chain info is not in use currently.
+
+ // input
+ if (!objcpy(&dWork.input, sWork->input,
+ bufferPoolSender, &baseBlocks, &baseBlockIndices)) {
+ LOG(ERROR) << "Invalid C2Work::input.";
+ return false;
+ }
+
+ // worklets
+ if (sWork->worklets.size() == 0) {
+ LOG(DEBUG) << "Work with no worklets.";
+ } else {
+ // Parcel the worklets.
+ hidl_vec<Worklet> &dWorklets = dWork.worklets;
+ dWorklets.resize(sWork->worklets.size());
+ size_t j = 0;
+ for (const std::unique_ptr<C2Worklet>& sWorklet : sWork->worklets)
+ {
+ if (!sWorklet) {
+ LOG(WARNING) << "Null C2Work::worklets["
+ << j << "].";
+ continue;
+ }
+ Worklet &dWorklet = dWorklets[j++];
+
+ // component id
+ dWorklet.componentId = static_cast<uint32_t>(
+ sWorklet->component);
+
+ // tunings
+ if (!createParamsBlob(&dWorklet.tunings, sWorklet->tunings)) {
+ LOG(ERROR) << "Invalid C2Work::worklets["
+ << j - 1 << "]->tunings.";
+ return false;
+ }
+
+ // failures
+ dWorklet.failures.resize(sWorklet->failures.size());
+ size_t k = 0;
+ for (const std::unique_ptr<C2SettingResult>& sFailure :
+ sWorklet->failures) {
+ if (!sFailure) {
+ LOG(WARNING) << "Null C2Work::worklets["
+ << j - 1 << "]->failures["
+ << k << "].";
+ continue;
+ }
+ if (!objcpy(&dWorklet.failures[k++], *sFailure)) {
+ LOG(ERROR) << "Invalid C2Work::worklets["
+ << j - 1 << "]->failures["
+ << k - 1 << "].";
+ return false;
+ }
+ }
+
+ // output
+ if (!objcpy(&dWorklet.output, sWorklet->output,
+ bufferPoolSender, &baseBlocks, &baseBlockIndices)) {
+ LOG(ERROR) << "Invalid C2Work::worklets["
+ << j - 1 << "]->output.";
+ return false;
+ }
+ }
+ }
+
+ // worklets processed
+ dWork.workletsProcessed = sWork->workletsProcessed;
+
+ // result
+ dWork.result = static_cast<Status>(sWork->result);
+ }
+
+ // Copy std::list<BaseBlock> to hidl_vec<BaseBlock>.
+ {
+ d->baseBlocks.resize(baseBlocks.size());
+ size_t i = 0;
+ for (const BaseBlock& baseBlock : baseBlocks) {
+ d->baseBlocks[i++] = baseBlock;
+ }
+ }
+
+ return true;
+}
+
+namespace /* unnamed */ {
+
+struct C2BaseBlock {
+ enum type_t {
+ LINEAR,
+ GRAPHIC,
+ };
+ type_t type;
+ std::shared_ptr<C2LinearBlock> linear;
+ std::shared_ptr<C2GraphicBlock> graphic;
+};
+
+// hidl_handle -> C2Fence
+// Note: File descriptors are not duplicated. The original file descriptor must
+// not be closed before the transaction is complete.
+bool objcpy(C2Fence* d, const hidl_handle& s) {
+ const native_handle_t* handle = s.getNativeHandle();
+ *d = _C2FenceFactory::CreateFromNativeHandle(handle);
+ return true;
+}
+
+// C2LinearBlock, vector<C2Param*>, C2Fence -> C2Buffer
+bool createLinearBuffer(
+ std::shared_ptr<C2Buffer>* buffer,
+ const std::shared_ptr<C2LinearBlock>& block,
+ const std::vector<C2Param*>& meta,
+ const C2Fence& fence) {
+ // Check the block meta. It should have exactly 1 C2Info:
+ // C2Hidl_RangeInfo.
+ if ((meta.size() != 1) || !meta[0]) {
+ LOG(ERROR) << "Invalid C2LinearBlock::meta.";
+ return false;
+ }
+ if (meta[0]->size() != sizeof(C2Hidl_RangeInfo)) {
+ LOG(ERROR) << "Invalid range info in C2LinearBlock.";
+ return false;
+ }
+ C2Hidl_RangeInfo *rangeInfo =
+ reinterpret_cast<C2Hidl_RangeInfo*>(meta[0]);
+
+ // Create C2Buffer from C2LinearBlock.
+ *buffer = C2Buffer::CreateLinearBuffer(block->share(
+ rangeInfo->offset, rangeInfo->length,
+ fence));
+ if (!(*buffer)) {
+ LOG(ERROR) << "CreateLinearBuffer failed.";
+ return false;
+ }
+ return true;
+}
+
+// C2GraphicBlock, vector<C2Param*>, C2Fence -> C2Buffer
+bool createGraphicBuffer(
+ std::shared_ptr<C2Buffer>* buffer,
+ const std::shared_ptr<C2GraphicBlock>& block,
+ const std::vector<C2Param*>& meta,
+ const C2Fence& fence) {
+ // Check the block meta. It should have exactly 1 C2Info:
+ // C2Hidl_RectInfo.
+ if ((meta.size() != 1) || !meta[0]) {
+ LOG(ERROR) << "Invalid C2GraphicBlock::meta.";
+ return false;
+ }
+ if (meta[0]->size() != sizeof(C2Hidl_RectInfo)) {
+ LOG(ERROR) << "Invalid rect info in C2GraphicBlock.";
+ return false;
+ }
+ C2Hidl_RectInfo *rectInfo =
+ reinterpret_cast<C2Hidl_RectInfo*>(meta[0]);
+
+ // Create C2Buffer from C2GraphicBlock.
+ *buffer = C2Buffer::CreateGraphicBuffer(block->share(
+ C2Rect(rectInfo->width, rectInfo->height).
+ at(rectInfo->left, rectInfo->top),
+ fence));
+ if (!(*buffer)) {
+ LOG(ERROR) << "CreateGraphicBuffer failed.";
+ return false;
+ }
+ return true;
+}
+
+// Buffer -> C2Buffer
+// Note: The native handles will be cloned.
+bool objcpy(std::shared_ptr<C2Buffer>* d, const Buffer& s,
+ const std::vector<C2BaseBlock>& baseBlocks) {
+ *d = nullptr;
+
+ // Currently, a non-null C2Buffer must contain exactly 1 block.
+ if (s.blocks.size() == 0) {
+ return true;
+ } else if (s.blocks.size() != 1) {
+ LOG(ERROR) << "Invalid Buffer: "
+ "Currently, a C2Buffer must contain exactly 1 block.";
+ return false;
+ }
+
+ const Block &sBlock = s.blocks[0];
+ if (sBlock.index >= baseBlocks.size()) {
+ LOG(ERROR) << "Invalid Buffer::blocks[0].index: "
+ "Array index out of range.";
+ return false;
+ }
+ const C2BaseBlock &baseBlock = baseBlocks[sBlock.index];
+
+ // Parse meta.
+ std::vector<C2Param*> sBlockMeta;
+ if (!parseParamsBlob(&sBlockMeta, sBlock.meta)) {
+ LOG(ERROR) << "Invalid Buffer::blocks[0].meta.";
+ return false;
+ }
+
+ // Copy fence.
+ C2Fence dFence;
+ if (!objcpy(&dFence, sBlock.fence)) {
+ LOG(ERROR) << "Invalid Buffer::blocks[0].fence.";
+ return false;
+ }
+
+ // Construct a block.
+ switch (baseBlock.type) {
+ case C2BaseBlock::LINEAR:
+ if (!createLinearBuffer(d, baseBlock.linear, sBlockMeta, dFence)) {
+ LOG(ERROR) << "Invalid C2BaseBlock::linear.";
+ return false;
+ }
+ break;
+ case C2BaseBlock::GRAPHIC:
+ if (!createGraphicBuffer(d, baseBlock.graphic, sBlockMeta, dFence)) {
+ LOG(ERROR) << "Invalid C2BaseBlock::graphic.";
+ return false;
+ }
+ break;
+ default:
+ LOG(ERROR) << "Invalid C2BaseBlock::type.";
+ return false;
+ }
+
+ // Parse info
+ std::vector<C2Param*> params;
+ if (!parseParamsBlob(¶ms, s.info)) {
+ LOG(ERROR) << "Invalid Buffer::info.";
+ return false;
+ }
+ for (C2Param* param : params) {
+ if (param == nullptr) {
+ LOG(ERROR) << "Null param in Buffer::info.";
+ return false;
+ }
+ std::shared_ptr<C2Param> c2param{
+ C2Param::Copy(*param).release()};
+ if (!c2param) {
+ LOG(ERROR) << "Invalid param in Buffer::info.";
+ return false;
+ }
+ c2_status_t status =
+ (*d)->setInfo(std::static_pointer_cast<C2Info>(c2param));
+ if (status != C2_OK) {
+ LOG(ERROR) << "C2Buffer::setInfo failed.";
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// InfoBuffer -> C2InfoBuffer
+bool objcpy(std::vector<C2InfoBuffer> *d, const InfoBuffer& s,
+ const std::vector<C2BaseBlock>& baseBlocks) {
+
+ // Currently, a non-null C2InfoBufer must contain exactly 1 block.
+ if (s.buffer.blocks.size() == 0) {
+ return true;
+ } else if (s.buffer.blocks.size() != 1) {
+ LOG(ERROR) << "Invalid InfoBuffer::Buffer "
+ "Currently, a C2InfoBuffer must contain exactly 1 block.";
+ return false;
+ }
+
+ const Block &sBlock = s.buffer.blocks[0];
+ if (sBlock.index >= baseBlocks.size()) {
+ LOG(ERROR) << "Invalid InfoBuffer::Buffer::blocks[0].index: "
+ "Array index out of range.";
+ return false;
+ }
+ const C2BaseBlock &baseBlock = baseBlocks[sBlock.index];
+
+ // Parse meta.
+ std::vector<C2Param*> sBlockMeta;
+ if (!parseParamsBlob(&sBlockMeta, sBlock.meta)) {
+ LOG(ERROR) << "Invalid InfoBuffer::Buffer::blocks[0].meta.";
+ return false;
+ }
+
+ // Copy fence.
+ C2Fence dFence;
+ if (!objcpy(&dFence, sBlock.fence)) {
+ LOG(ERROR) << "Invalid InfoBuffer::Buffer::blocks[0].fence.";
+ return false;
+ }
+
+ // Construct a block.
+ switch (baseBlock.type) {
+ case C2BaseBlock::LINEAR:
+ if (sBlockMeta.size() == 1 && sBlockMeta[0] != nullptr &&
+ sBlockMeta[0]->size() == sizeof(C2Hidl_RangeInfo)) {
+ C2Hidl_RangeInfo *rangeInfo =
+ reinterpret_cast<C2Hidl_RangeInfo*>(sBlockMeta[0]);
+ d->emplace_back(C2InfoBuffer::CreateLinearBuffer(
+ s.index,
+ baseBlock.linear->share(
+ rangeInfo->offset, rangeInfo->length, dFence)));
+ return true;
+ }
+ LOG(ERROR) << "Invalid Meta for C2BaseBlock::Linear InfoBuffer.";
+ break;
+ case C2BaseBlock::GRAPHIC:
+ // It's not used now
+ LOG(ERROR) << "Non-Used C2BaseBlock::type for InfoBuffer.";
+ break;
+ default:
+ LOG(ERROR) << "Invalid C2BaseBlock::type for InfoBuffer.";
+ break;
+ }
+
+ return false;
+}
+
+// FrameData -> C2FrameData
+bool objcpy(C2FrameData* d, const FrameData& s,
+ const std::vector<C2BaseBlock>& baseBlocks) {
+ d->flags = static_cast<C2FrameData::flags_t>(s.flags);
+ if (!objcpy(&d->ordinal, s.ordinal)) {
+ LOG(ERROR) << "Invalid FrameData::ordinal.";
+ return false;
+ }
+ d->buffers.clear();
+ d->buffers.reserve(s.buffers.size());
+ for (const Buffer& sBuffer : s.buffers) {
+ std::shared_ptr<C2Buffer> dBuffer;
+ if (!objcpy(&dBuffer, sBuffer, baseBlocks)) {
+ LOG(ERROR) << "Invalid FrameData::buffers.";
+ return false;
+ }
+ d->buffers.emplace_back(dBuffer);
+ }
+
+ std::vector<C2Param*> params;
+ if (!parseParamsBlob(¶ms, s.configUpdate)) {
+ LOG(ERROR) << "Invalid FrameData::configUpdate.";
+ return false;
+ }
+ d->configUpdate.clear();
+ for (C2Param* param : params) {
+ d->configUpdate.emplace_back(C2Param::Copy(*param));
+ if (!d->configUpdate.back()) {
+ LOG(ERROR) << "Unexpected error while parsing "
+ "FrameData::configUpdate.";
+ return false;
+ }
+ }
+
+ d->infoBuffers.clear();
+ if (s.infoBuffers.size() == 0) {
+ // InfoBuffer is optional
+ return true;
+ }
+ d->infoBuffers.reserve(s.infoBuffers.size());
+ for (const InfoBuffer &sInfoBuffer: s.infoBuffers) {
+ if (!objcpy(&(d->infoBuffers), sInfoBuffer, baseBlocks)) {
+ LOG(ERROR) << "Invalid Framedata::infoBuffers.";
+ return false;
+ }
+ }
+ return true;
+}
+
+// BaseBlock -> C2BaseBlock
+bool objcpy(C2BaseBlock* d, const BaseBlock& s) {
+ switch (s.getDiscriminator()) {
+ case BaseBlock::hidl_discriminator::nativeBlock: {
+ if (s.nativeBlock() == nullptr) {
+ LOG(ERROR) << "Null BaseBlock::nativeBlock handle";
+ return false;
+ }
+ native_handle_t* sHandle =
+ native_handle_clone(s.nativeBlock());
+ if (sHandle == nullptr) {
+ LOG(ERROR) << "Null BaseBlock::nativeBlock.";
+ return false;
+ }
+ const C2Handle *sC2Handle =
+ reinterpret_cast<const C2Handle*>(sHandle);
+
+ d->linear = _C2BlockFactory::CreateLinearBlock(sC2Handle);
+ if (d->linear) {
+ d->type = C2BaseBlock::LINEAR;
+ return true;
+ }
+
+ d->graphic = _C2BlockFactory::CreateGraphicBlock(sC2Handle);
+ if (d->graphic) {
+ d->type = C2BaseBlock::GRAPHIC;
+ return true;
+ }
+
+ LOG(ERROR) << "Unknown handle type in BaseBlock::nativeBlock.";
+ if (sHandle) {
+ native_handle_close(sHandle);
+ native_handle_delete(sHandle);
+ }
+ return false;
+ }
+ case BaseBlock::hidl_discriminator::pooledBlock: {
+ const BufferStatusMessage &bpMessage =
+ s.pooledBlock();
+ sp<ClientManager> bp = ClientManager::getInstance();
+ std::shared_ptr<BufferPoolData> bpData;
+ native_handle_t *cHandle;
+ ResultStatus bpStatus = bp->receive(
+ bpMessage.connectionId,
+ bpMessage.transactionId,
+ bpMessage.bufferId,
+ bpMessage.timestampUs,
+ &cHandle,
+ &bpData);
+ if (bpStatus != ResultStatus::OK) {
+ LOG(ERROR) << "Failed to receive buffer from bufferpool -- "
+ << "resultStatus = " << underlying_value(bpStatus)
+ << ".";
+ return false;
+ } else if (!bpData) {
+ LOG(ERROR) << "No data in bufferpool transaction.";
+ return false;
+ }
+
+ d->linear = _C2BlockFactory::CreateLinearBlock(cHandle, bpData);
+ if (d->linear) {
+ d->type = C2BaseBlock::LINEAR;
+ return true;
+ }
+
+ d->graphic = _C2BlockFactory::CreateGraphicBlock(cHandle, bpData);
+ if (d->graphic) {
+ d->type = C2BaseBlock::GRAPHIC;
+ return true;
+ }
+ if (cHandle) {
+ // Though we got cloned handle, creating block failed.
+ native_handle_close(cHandle);
+ native_handle_delete(cHandle);
+ }
+
+ LOG(ERROR) << "Unknown handle type in BaseBlock::pooledBlock.";
+ return false;
+ }
+ default:
+ LOG(ERROR) << "Unrecognized BaseBlock's discriminator with "
+ << "underlying value "
+ << underlying_value(s.getDiscriminator()) << ".";
+ return false;
+ }
+}
+
+} // unnamed namespace
+
+// WorkBundle -> std::list<std::unique_ptr<C2Work>>
+bool objcpy(std::list<std::unique_ptr<C2Work>>* d, const WorkBundle& s) {
+ // Convert BaseBlocks to C2BaseBlocks.
+ std::vector<C2BaseBlock> dBaseBlocks(s.baseBlocks.size());
+ for (size_t i = 0; i < s.baseBlocks.size(); ++i) {
+ if (!objcpy(&dBaseBlocks[i], s.baseBlocks[i])) {
+ LOG(ERROR) << "Invalid WorkBundle::baseBlocks["
+ << i << "].";
+ return false;
+ }
+ }
+
+ d->clear();
+ for (const Work& sWork : s.works) {
+ d->emplace_back(std::make_unique<C2Work>());
+ C2Work& dWork = *d->back();
+
+ // chain info is not in use currently.
+
+ // input
+ if (!objcpy(&dWork.input, sWork.input, dBaseBlocks)) {
+ LOG(ERROR) << "Invalid Work::input.";
+ return false;
+ }
+
+ // worklet(s)
+ dWork.worklets.clear();
+ for (const Worklet& sWorklet : sWork.worklets) {
+ std::unique_ptr<C2Worklet> dWorklet = std::make_unique<C2Worklet>();
+
+ // component id
+ dWorklet->component = static_cast<c2_node_id_t>(
+ sWorklet.componentId);
+
+ // tunings
+ if (!copyParamsFromBlob(&dWorklet->tunings, sWorklet.tunings)) {
+ LOG(ERROR) << "Invalid Worklet::tunings";
+ return false;
+ }
+
+ // failures
+ dWorklet->failures.clear();
+ dWorklet->failures.reserve(sWorklet.failures.size());
+ for (const SettingResult& sFailure : sWorklet.failures) {
+ std::unique_ptr<C2SettingResult> dFailure;
+ if (!objcpy(&dFailure, sFailure)) {
+ LOG(ERROR) << "Invalid Worklet::failures.";
+ return false;
+ }
+ dWorklet->failures.emplace_back(std::move(dFailure));
+ }
+
+ // output
+ if (!objcpy(&dWorklet->output, sWorklet.output, dBaseBlocks)) {
+ LOG(ERROR) << "Invalid Worklet::output.";
+ return false;
+ }
+
+ dWork.worklets.emplace_back(std::move(dWorklet));
+ }
+
+ // workletsProcessed
+ dWork.workletsProcessed = sWork.workletsProcessed;
+
+ // result
+ dWork.result = static_cast<c2_status_t>(sWork.result);
+ }
+
+ return true;
+}
+
+constexpr size_t PARAMS_ALIGNMENT = 8; // 64-bit alignment
+static_assert(PARAMS_ALIGNMENT % alignof(C2Param) == 0, "C2Param alignment mismatch");
+static_assert(PARAMS_ALIGNMENT % alignof(C2Info) == 0, "C2Param alignment mismatch");
+static_assert(PARAMS_ALIGNMENT % alignof(C2Tuning) == 0, "C2Param alignment mismatch");
+
+// Params -> std::vector<C2Param*>
+bool parseParamsBlob(std::vector<C2Param*> *params, const hidl_vec<uint8_t> &blob) {
+ // assuming blob is const here
+ size_t size = blob.size();
+ size_t ix = 0;
+ size_t old_ix = 0;
+ const uint8_t *data = blob.data();
+ C2Param *p = nullptr;
+
+ do {
+ p = C2ParamUtils::ParseFirst(data + ix, size - ix);
+ if (p) {
+ params->emplace_back(p);
+ old_ix = ix;
+ ix += p->size();
+ ix = align(ix, PARAMS_ALIGNMENT);
+ if (ix <= old_ix || ix > size) {
+ android_errorWriteLog(0x534e4554, "238083570");
+ break;
+ }
+ }
+ } while (p);
+
+ if (ix != size) {
+ LOG(ERROR) << "parseParamsBlob -- inconsistent sizes.";
+ return false;
+ }
+ return true;
+}
+
+namespace /* unnamed */ {
+
+/**
+ * Concatenates a list of C2Params into a params blob. T is a container type
+ * whose member type is compatible with C2Param*.
+ *
+ * \param[out] blob target blob
+ * \param[in] params parameters to concatenate
+ * \retval C2_OK if the blob was successfully created
+ * \retval C2_BAD_VALUE if the blob was not successful created (this only
+ * happens if the parameters were not const)
+ */
+template <typename T>
+bool _createParamsBlob(hidl_vec<uint8_t> *blob, const T ¶ms) {
+ // assuming the parameter values are const
+ size_t size = 0;
+ for (const auto &p : params) {
+ if (!p) {
+ continue;
+ }
+ size += p->size();
+ size = align(size, PARAMS_ALIGNMENT);
+ }
+ blob->resize(size);
+ size_t ix = 0;
+ for (const auto &p : params) {
+ if (!p) {
+ continue;
+ }
+ // NEVER overwrite even if param values (e.g. size) changed
+ size_t paramSize = std::min(p->size(), size - ix);
+ std::copy(
+ reinterpret_cast<const uint8_t*>(&*p),
+ reinterpret_cast<const uint8_t*>(&*p) + paramSize,
+ &(*blob)[ix]);
+ ix += paramSize;
+ ix = align(ix, PARAMS_ALIGNMENT);
+ }
+ blob->resize(ix);
+ if (ix != size) {
+ LOG(ERROR) << "createParamsBlob -- inconsistent sizes.";
+ return false;
+ }
+ return true;
+}
+
+/**
+ * Parses a params blob and create a vector of new T objects that contain copies
+ * of the params in the blob. T is C2Param or its compatible derived class.
+ *
+ * \param[out] params the resulting vector
+ * \param[in] blob parameter blob to parse
+ * \retval C2_OK if the full blob was parsed and params was constructed
+ * \retval C2_BAD_VALUE otherwise
+ */
+template <typename T>
+bool _copyParamsFromBlob(
+ std::vector<std::unique_ptr<T>>* params,
+ Params blob) {
+
+ std::vector<C2Param*> paramPointers;
+ if (!parseParamsBlob(¶mPointers, blob)) {
+ LOG(ERROR) << "copyParamsFromBlob -- failed to parse.";
+ return false;
+ }
+
+ params->resize(paramPointers.size());
+ size_t i = 0;
+ for (C2Param* const& paramPointer : paramPointers) {
+ if (!paramPointer) {
+ LOG(ERROR) << "copyParamsFromBlob -- null paramPointer.";
+ return false;
+ }
+ (*params)[i++].reset(reinterpret_cast<T*>(
+ C2Param::Copy(*paramPointer).release()));
+ }
+ return true;
+}
+
+} // unnamed namespace
+
+// std::vector<const C2Param*> -> Params
+bool createParamsBlob(
+ hidl_vec<uint8_t> *blob,
+ const std::vector<const C2Param*> ¶ms) {
+ return _createParamsBlob(blob, params);
+}
+
+// std::vector<C2Param*> -> Params
+bool createParamsBlob(
+ hidl_vec<uint8_t> *blob,
+ const std::vector<C2Param*> ¶ms) {
+ return _createParamsBlob(blob, params);
+}
+
+// std::vector<std::unique_ptr<C2Param>> -> Params
+bool createParamsBlob(
+ hidl_vec<uint8_t> *blob,
+ const std::vector<std::unique_ptr<C2Param>> ¶ms) {
+ return _createParamsBlob(blob, params);
+}
+
+// std::vector<std::unique_ptr<C2Tuning>> -> Params
+bool createParamsBlob(
+ hidl_vec<uint8_t> *blob,
+ const std::vector<std::unique_ptr<C2Tuning>> ¶ms) {
+ return _createParamsBlob(blob, params);
+}
+
+// std::vector<std::shared_ptr<const C2Info>> -> Params
+bool createParamsBlob(
+ hidl_vec<uint8_t> *blob,
+ const std::vector<std::shared_ptr<const C2Info>> ¶ms) {
+ return _createParamsBlob(blob, params);
+}
+
+// Params -> std::vector<std::unique_ptr<C2Param>>
+bool copyParamsFromBlob(
+ std::vector<std::unique_ptr<C2Param>>* params,
+ Params blob) {
+ return _copyParamsFromBlob(params, blob);
+}
+
+// Params -> std::vector<std::unique_ptr<C2Tuning>>
+bool copyParamsFromBlob(
+ std::vector<std::unique_ptr<C2Tuning>>* params,
+ Params blob) {
+ return _copyParamsFromBlob(params, blob);
+}
+
+// Params -> update std::vector<std::unique_ptr<C2Param>>
+bool updateParamsFromBlob(
+ const std::vector<C2Param*>& params,
+ const Params& blob) {
+ std::unordered_map<uint32_t, C2Param*> index2param;
+ for (C2Param* const& param : params) {
+ if (!param) {
+ LOG(ERROR) << "updateParamsFromBlob -- null output param.";
+ return false;
+ }
+ if (index2param.find(param->index()) == index2param.end()) {
+ index2param.emplace(param->index(), param);
+ }
+ }
+
+ std::vector<C2Param*> paramPointers;
+ if (!parseParamsBlob(¶mPointers, blob)) {
+ LOG(ERROR) << "updateParamsFromBlob -- failed to parse.";
+ return false;
+ }
+
+ for (C2Param* const& paramPointer : paramPointers) {
+ if (!paramPointer) {
+ LOG(ERROR) << "updateParamsFromBlob -- null input param.";
+ return false;
+ }
+ decltype(index2param)::iterator i = index2param.find(
+ paramPointer->index());
+ if (i == index2param.end()) {
+ LOG(DEBUG) << "updateParamsFromBlob -- index "
+ << paramPointer->index() << " not found. Skipping...";
+ continue;
+ }
+ if (!i->second->updateFrom(*paramPointer)) {
+ LOG(ERROR) << "updateParamsFromBlob -- size mismatch: "
+ << params.size() << " vs " << paramPointer->size()
+ << " (index = " << i->first << ").";
+ return false;
+ }
+ }
+ return true;
+}
+
+// Convert BufferPool ResultStatus to c2_status_t.
+c2_status_t toC2Status(ResultStatus rs) {
+ switch (rs) {
+ case ResultStatus::OK:
+ return C2_OK;
+ case ResultStatus::NO_MEMORY:
+ return C2_NO_MEMORY;
+ case ResultStatus::ALREADY_EXISTS:
+ return C2_DUPLICATE;
+ case ResultStatus::NOT_FOUND:
+ return C2_NOT_FOUND;
+ case ResultStatus::CRITICAL_ERROR:
+ return C2_CORRUPTED;
+ default:
+ LOG(WARNING) << "Unrecognized BufferPool ResultStatus: "
+ << static_cast<int32_t>(rs) << ".";
+ return C2_CORRUPTED;
+ }
+}
+
+namespace /* unnamed */ {
+
+template <typename BlockProcessor>
+void forEachBlock(C2FrameData& frameData,
+ BlockProcessor process) {
+ for (const std::shared_ptr<C2Buffer>& buffer : frameData.buffers) {
+ if (buffer) {
+ for (const C2ConstGraphicBlock& block :
+ buffer->data().graphicBlocks()) {
+ process(block);
+ }
+ }
+ }
+}
+
+template <typename BlockProcessor>
+void forEachBlock(const std::list<std::unique_ptr<C2Work>>& workList,
+ BlockProcessor process,
+ bool processInput, bool processOutput) {
+ for (const std::unique_ptr<C2Work>& work : workList) {
+ if (!work) {
+ continue;
+ }
+ if (processInput) {
+ forEachBlock(work->input, process);
+ }
+ if (processOutput) {
+ for (const std::unique_ptr<C2Worklet>& worklet : work->worklets) {
+ if (worklet) {
+ forEachBlock(worklet->output,
+ process);
+ }
+ }
+ }
+ }
+}
+
+} // unnamed namespace
+
+bool beginTransferBufferQueueBlock(const C2ConstGraphicBlock& block) {
+ std::shared_ptr<_C2BlockPoolData> data =
+ _C2BlockFactory::GetGraphicBlockPoolData(block);
+ if (data && _C2BlockFactory::GetBufferQueueData(data)) {
+ _C2BlockFactory::BeginTransferBlockToClient(data);
+ return true;
+ }
+ return false;
+}
+
+void beginTransferBufferQueueBlocks(
+ const std::list<std::unique_ptr<C2Work>>& workList,
+ bool processInput, bool processOutput) {
+ forEachBlock(workList, beginTransferBufferQueueBlock,
+ processInput, processOutput);
+}
+
+bool endTransferBufferQueueBlock(
+ const C2ConstGraphicBlock& block,
+ bool transfer) {
+ std::shared_ptr<_C2BlockPoolData> data =
+ _C2BlockFactory::GetGraphicBlockPoolData(block);
+ if (data && _C2BlockFactory::GetBufferQueueData(data)) {
+ _C2BlockFactory::EndTransferBlockToClient(data, transfer);
+ return true;
+ }
+ return false;
+}
+
+void endTransferBufferQueueBlocks(
+ const std::list<std::unique_ptr<C2Work>>& workList,
+ bool transfer,
+ bool processInput, bool processOutput) {
+ forEachBlock(workList,
+ std::bind(endTransferBufferQueueBlock,
+ std::placeholders::_1, transfer),
+ processInput, processOutput);
+}
+
+bool displayBufferQueueBlock(const C2ConstGraphicBlock& block) {
+ std::shared_ptr<_C2BlockPoolData> data =
+ _C2BlockFactory::GetGraphicBlockPoolData(block);
+ if (data && _C2BlockFactory::GetBufferQueueData(data)) {
+ _C2BlockFactory::DisplayBlockToBufferQueue(data);
+ return true;
+ }
+ return false;
+}
+
+} // namespace utils
+} // namespace V1_0
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
diff --git a/media/codec2/hal/common/include/codec2/common/ParamTypes.h b/media/codec2/hal/common/include/codec2/common/ParamTypes.h
new file mode 100644
index 0000000..5446100
--- /dev/null
+++ b/media/codec2/hal/common/include/codec2/common/ParamTypes.h
@@ -0,0 +1,807 @@
+/*
+ * Copyright 2018 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_PARAM_TYPES_H
+#define CODEC2_COMMON_PARAM_TYPES_H
+
+#ifndef LOG_TAG
+#define LOG_TAG "Codec2-ParamTypes"
+#endif
+#include <android-base/logging.h>
+
+#include <log/log_safetynet.h>
+#include <media/stagefright/foundation/AUtils.h>
+
+#include <C2Component.h>
+#include <C2Param.h>
+#include <C2ParamInternal.h>
+#include <util/C2ParamUtils.h>
+
+#include <algorithm>
+#include <unordered_map>
+
+namespace android {
+
+template <typename EnumClass>
+typename std::underlying_type<EnumClass>::type underlying_value(EnumClass x) {
+ return static_cast<typename std::underlying_type<EnumClass>::type>(x);
+}
+
+template <typename Common, typename DstVector, typename SrcVector>
+void copyVector(DstVector* d, const SrcVector& s) {
+ static_assert(sizeof(Common) == sizeof(decltype((*d)[0])),
+ "DstVector's component size does not match Common");
+ static_assert(sizeof(Common) == sizeof(decltype(s[0])),
+ "SrcVector's component size does not match Common");
+ d->resize(s.size());
+ std::copy(
+ reinterpret_cast<const Common*>(&s[0]),
+ reinterpret_cast<const Common*>(&s[0] + s.size()),
+ reinterpret_cast<Common*>(&(*d)[0]));
+}
+
+// {offset, size} -> FieldId
+template <typename FieldId>
+void SetFieldId(FieldId *d, uint32_t offset, uint32_t size) {
+ d->offset = offset;
+ d->size = size;
+}
+
+// FieldId -> offset
+template <typename FieldId>
+uint32_t GetOffsetFromFieldId(const FieldId &s) {
+ return s.offset;
+}
+
+// FieldId -> size
+template <typename FieldId>
+uint32_t GetSizeFromFieldId(const FieldId &s) {
+ return s.size;
+}
+
+// C2ParamField -> ParamField
+template <typename ParamField>
+bool objcpy(ParamField *d, const C2ParamField &s) {
+ d->index = static_cast<decltype(d->index)>(_C2ParamInspector::GetIndex(s));
+ SetFieldId(
+ &d->fieldId,
+ static_cast<uint32_t>(_C2ParamInspector::GetOffset(s)),
+ static_cast<uint32_t>(_C2ParamInspector::GetSize(s)));
+ return true;
+}
+
+template <typename ParamField>
+struct C2ParamFieldBuilder : public C2ParamField {
+ C2ParamFieldBuilder() : C2ParamField(
+ static_cast<C2Param::Index>(static_cast<uint32_t>(0)), 0, 0) {
+ }
+ // ParamField -> C2ParamField
+ C2ParamFieldBuilder(const ParamField& s) : C2ParamField(
+ static_cast<C2Param::Index>(static_cast<uint32_t>(s.index)),
+ static_cast<uint32_t>(GetOffsetFromFieldId(s.fieldId)),
+ static_cast<uint32_t>(GetSizeFromFieldId(s.fieldId))) {
+ }
+};
+
+// C2WorkOrdinalStruct -> WorkOrdinal
+template <typename WorkOrdinal>
+bool objcpy(WorkOrdinal *d, const C2WorkOrdinalStruct &s) {
+ d->frameIndex = static_cast<uint64_t>(s.frameIndex.peeku());
+ d->timestampUs = static_cast<uint64_t>(s.timestamp.peeku());
+ d->customOrdinal = static_cast<uint64_t>(s.customOrdinal.peeku());
+ return true;
+}
+
+// WorkOrdinal -> C2WorkOrdinalStruct
+template <typename WorkOrdinal>
+bool objcpy(C2WorkOrdinalStruct *d, const WorkOrdinal &s) {
+ d->frameIndex = c2_cntr64_t(s.frameIndex);
+ d->timestamp = c2_cntr64_t(s.timestampUs);
+ d->customOrdinal = c2_cntr64_t(s.customOrdinal);
+ return true;
+}
+
+// C2FieldSupportedValues::range's type -> ValueRange
+template <typename ValueRange>
+bool objcpy(
+ ValueRange* d,
+ const decltype(C2FieldSupportedValues::range)& s) {
+ d->min = static_cast<decltype(d->min)>(s.min.u64);
+ d->max = static_cast<decltype(d->max)>(s.max.u64);
+ d->step = static_cast<decltype(d->step)>(s.step.u64);
+ d->num = static_cast<decltype(d->num)>(s.num.u64);
+ d->denom = static_cast<decltype(d->denom)>(s.denom.u64);
+ return true;
+}
+
+// ValueRange -> C2FieldSupportedValues::range's type
+template <typename ValueRange>
+bool objcpy(
+ decltype(C2FieldSupportedValues::range)* d,
+ const ValueRange& s) {
+ d->min.u64 = static_cast<uint64_t>(s.min);
+ d->max.u64 = static_cast<uint64_t>(s.max);
+ d->step.u64 = static_cast<uint64_t>(s.step);
+ d->num.u64 = static_cast<uint64_t>(s.num);
+ d->denom.u64 = static_cast<uint64_t>(s.denom);
+ return true;
+}
+
+template <typename Status>
+void SetStatus(Status *dst, c2_status_t src) {
+ *dst = static_cast<Status>(src);
+}
+
+template <typename Status>
+c2_status_t GetStatus(const Status &status) {
+ return static_cast<c2_status_t>(status);
+}
+
+// C2FieldSupportedValues -> FieldSupportedValues
+template <typename FieldSupportedValues>
+bool objcpy(FieldSupportedValues *d, const C2FieldSupportedValues &s);
+
+// FieldSupportedValues -> C2FieldSupportedValues
+template <typename FieldSupportedValues>
+bool objcpy(C2FieldSupportedValues *d, const FieldSupportedValues &s);
+
+// C2FieldSupportedValuesQuery -> FieldSupportedValuesQuery, FieldSupportedValuesQueryResult
+template <typename FieldSupportedValuesQueryPtr>
+bool objcpy(
+ FieldSupportedValuesQueryPtr dq,
+ nullptr_t,
+ const C2FieldSupportedValuesQuery& s) {
+ static_assert(!std::is_null_pointer_v<FieldSupportedValuesQueryPtr>);
+ static_assert(std::is_pointer_v<FieldSupportedValuesQueryPtr>);
+ typedef std::remove_pointer_t<FieldSupportedValuesQueryPtr> FieldSupportedValuesQuery;
+ if (!dq) {
+ return false;
+ }
+ if (!objcpy(&dq->field, s.field())) {
+ LOG(ERROR) << "Invalid C2FieldSupportedValuesQuery::field.";
+ return false;
+ }
+ switch (s.type()) {
+ case C2FieldSupportedValuesQuery::POSSIBLE:
+ dq->type = FieldSupportedValuesQuery::Type::POSSIBLE;
+ break;
+ case C2FieldSupportedValuesQuery::CURRENT:
+ dq->type = FieldSupportedValuesQuery::Type::CURRENT;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized C2FieldSupportedValuesQuery::type_t "
+ << "with underlying value " << underlying_value(s.type())
+ << ".";
+ dq->type = static_cast<decltype(dq->type)>(s.type());
+ }
+ return true;
+}
+
+template <typename FieldSupportedValuesQueryResultPtr>
+bool objcpy(
+ nullptr_t,
+ FieldSupportedValuesQueryResultPtr dr,
+ const C2FieldSupportedValuesQuery& s) {
+ static_assert(!std::is_null_pointer_v<FieldSupportedValuesQueryResultPtr>);
+ static_assert(std::is_pointer_v<FieldSupportedValuesQueryResultPtr>);
+ if (!dr) {
+ return false;
+ }
+ SetStatus(&dr->status, s.status);
+ return objcpy(&dr->values, s.values);
+}
+
+template <typename FieldSupportedValuesQueryPtr, typename FieldSupportedValuesQueryResultPtr>
+bool objcpy(
+ FieldSupportedValuesQueryPtr dq,
+ FieldSupportedValuesQueryResultPtr dr,
+ const C2FieldSupportedValuesQuery& s) {
+ if (!objcpy(dq, nullptr, s)) {
+ return false;
+ }
+ return objcpy(nullptr, dr, s);
+}
+
+// FieldSupportedValuesQuery -> C2FieldSupportedValuesQuery
+template <typename FieldSupportedValuesQuery>
+bool objcpy(
+ C2FieldSupportedValuesQuery* d,
+ const FieldSupportedValuesQuery& s) {
+ C2FieldSupportedValuesQuery::type_t dType;
+ switch (s.type) {
+ case FieldSupportedValuesQuery::Type::POSSIBLE:
+ dType = C2FieldSupportedValuesQuery::POSSIBLE;
+ break;
+ case FieldSupportedValuesQuery::Type::CURRENT:
+ dType = C2FieldSupportedValuesQuery::CURRENT;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized FieldSupportedValuesQuery::Type "
+ << "with underlying value " << underlying_value(s.type)
+ << ".";
+ dType = static_cast<C2FieldSupportedValuesQuery::type_t>(s.type);
+ }
+ *d = C2FieldSupportedValuesQuery(C2ParamFieldBuilder(s.field), dType);
+ return true;
+}
+
+// FieldSupportedValuesQuery, FieldSupportedValuesQueryResult ->
+// C2FieldSupportedValuesQuery
+template <typename FieldSupportedValuesQuery,
+ typename FieldSupportedValuesQueryResult>
+bool objcpy(
+ C2FieldSupportedValuesQuery* d,
+ const FieldSupportedValuesQuery& sq,
+ const FieldSupportedValuesQueryResult& sr) {
+ if (!objcpy(d, sq)) {
+ LOG(ERROR) << "Invalid FieldSupportedValuesQuery.";
+ return false;
+ }
+ d->status = GetStatus(sr.status);
+ if (!objcpy(&d->values, sr.values)) {
+ LOG(ERROR) << "Invalid FieldSupportedValuesQueryResult::values.";
+ return false;
+ }
+ return true;
+}
+
+// C2Component::Traits -> IComponentStore::ComponentTraits
+template <typename ComponentTraits>
+bool objcpy(
+ ComponentTraits *d,
+ const C2Component::Traits &s) {
+ d->name = s.name;
+
+ switch (s.domain) {
+ case C2Component::DOMAIN_VIDEO:
+ d->domain = ComponentTraits::Domain::VIDEO;
+ break;
+ case C2Component::DOMAIN_AUDIO:
+ d->domain = ComponentTraits::Domain::AUDIO;
+ break;
+ case C2Component::DOMAIN_IMAGE:
+ d->domain = ComponentTraits::Domain::IMAGE;
+ break;
+ case C2Component::DOMAIN_OTHER:
+ d->domain = ComponentTraits::Domain::OTHER;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized C2Component::domain_t "
+ << "with underlying value " << underlying_value(s.domain)
+ << ".";
+ d->domain = static_cast<decltype(d->domain)>(s.domain);
+ }
+
+ switch (s.kind) {
+ case C2Component::KIND_DECODER:
+ d->kind = ComponentTraits::Kind::DECODER;
+ break;
+ case C2Component::KIND_ENCODER:
+ d->kind = ComponentTraits::Kind::ENCODER;
+ break;
+ case C2Component::KIND_OTHER:
+ d->kind = ComponentTraits::Kind::OTHER;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized C2Component::kind_t "
+ << "with underlying value " << underlying_value(s.kind)
+ << ".";
+ d->kind = static_cast<decltype(d->kind)>(s.kind);
+ }
+
+ d->rank = static_cast<uint32_t>(s.rank);
+
+ d->mediaType = s.mediaType;
+
+ d->aliases.resize(s.aliases.size());
+ for (size_t ix = s.aliases.size(); ix > 0; ) {
+ --ix;
+ d->aliases[ix] = s.aliases[ix];
+ }
+ return true;
+}
+
+// ComponentTraits -> C2Component::Traits, std::unique_ptr<std::vector<std::string>>
+template <typename ComponentTraits>
+bool objcpy(
+ C2Component::Traits* d,
+ const ComponentTraits& s) {
+ d->name = s.name.c_str();
+
+ switch (s.domain) {
+ case ComponentTraits::Domain::VIDEO:
+ d->domain = C2Component::DOMAIN_VIDEO;
+ break;
+ case ComponentTraits::Domain::AUDIO:
+ d->domain = C2Component::DOMAIN_AUDIO;
+ break;
+ case ComponentTraits::Domain::IMAGE:
+ d->domain = C2Component::DOMAIN_IMAGE;
+ break;
+ case ComponentTraits::Domain::OTHER:
+ d->domain = C2Component::DOMAIN_OTHER;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized ComponentTraits::Domain "
+ << "with underlying value " << underlying_value(s.domain)
+ << ".";
+ d->domain = static_cast<C2Component::domain_t>(s.domain);
+ }
+
+ switch (s.kind) {
+ case ComponentTraits::Kind::DECODER:
+ d->kind = C2Component::KIND_DECODER;
+ break;
+ case ComponentTraits::Kind::ENCODER:
+ d->kind = C2Component::KIND_ENCODER;
+ break;
+ case ComponentTraits::Kind::OTHER:
+ d->kind = C2Component::KIND_OTHER;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized ComponentTraits::Kind "
+ << "with underlying value " << underlying_value(s.kind)
+ << ".";
+ d->kind = static_cast<C2Component::kind_t>(s.kind);
+ }
+
+ d->rank = static_cast<C2Component::rank_t>(s.rank);
+ d->mediaType = s.mediaType.c_str();
+ d->aliases.resize(s.aliases.size());
+ for (size_t i = 0; i < s.aliases.size(); ++i) {
+ d->aliases[i] = s.aliases[i];
+ }
+ return true;
+}
+
+// C2ParamFieldValues -> ParamFieldValues
+template <typename ParamFieldValues>
+bool objcpy(
+ ParamFieldValues *d,
+ const C2ParamFieldValues &s) {
+ if (!objcpy(&d->paramOrField, s.paramOrField)) {
+ LOG(ERROR) << "Invalid C2ParamFieldValues::paramOrField.";
+ return false;
+ }
+ if (s.values) {
+ d->values.resize(1);
+ if (!objcpy(&d->values[0], *s.values)) {
+ LOG(ERROR) << "Invalid C2ParamFieldValues::values.";
+ return false;
+ }
+ return true;
+ }
+ d->values.resize(0);
+ return true;
+}
+
+// ParamFieldValues -> C2ParamFieldValues
+template <typename ParamFieldValues>
+bool objcpy(
+ C2ParamFieldValues *d,
+ const ParamFieldValues &s) {
+ d->paramOrField = C2ParamFieldBuilder(s.paramOrField);
+ if (s.values.size() == 1) {
+ d->values = std::make_unique<C2FieldSupportedValues>();
+ if (!objcpy(d->values.get(), s.values[0])) {
+ LOG(ERROR) << "Invalid ParamFieldValues::values.";
+ return false;
+ }
+ return true;
+ } else if (s.values.size() == 0) {
+ d->values.reset();
+ return true;
+ }
+ LOG(ERROR) << "Invalid ParamFieldValues: "
+ "Two or more FieldSupportedValues objects exist in "
+ "ParamFieldValues. "
+ "Only zero or one is allowed.";
+ return false;
+}
+
+// C2SettingResult -> SettingResult
+template <typename SettingResult>
+bool objcpy(
+ SettingResult *d,
+ const C2SettingResult &s) {
+ switch (s.failure) {
+ case C2SettingResult::BAD_TYPE:
+ d->failure = SettingResult::Failure::BAD_TYPE;
+ break;
+ case C2SettingResult::BAD_PORT:
+ d->failure = SettingResult::Failure::BAD_PORT;
+ break;
+ case C2SettingResult::BAD_INDEX:
+ d->failure = SettingResult::Failure::BAD_INDEX;
+ break;
+ case C2SettingResult::READ_ONLY:
+ d->failure = SettingResult::Failure::READ_ONLY;
+ break;
+ case C2SettingResult::MISMATCH:
+ d->failure = SettingResult::Failure::MISMATCH;
+ break;
+ case C2SettingResult::BAD_VALUE:
+ d->failure = SettingResult::Failure::BAD_VALUE;
+ break;
+ case C2SettingResult::CONFLICT:
+ d->failure = SettingResult::Failure::CONFLICT;
+ break;
+ case C2SettingResult::UNSUPPORTED:
+ d->failure = SettingResult::Failure::UNSUPPORTED;
+ break;
+ case C2SettingResult::INFO_BAD_VALUE:
+ d->failure = SettingResult::Failure::INFO_BAD_VALUE;
+ break;
+ case C2SettingResult::INFO_CONFLICT:
+ d->failure = SettingResult::Failure::INFO_CONFLICT;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized C2SettingResult::Failure "
+ << "with underlying value " << underlying_value(s.failure)
+ << ".";
+ d->failure = static_cast<decltype(d->failure)>(s.failure);
+ }
+ if (!objcpy(&d->field, s.field)) {
+ LOG(ERROR) << "Invalid C2SettingResult::field.";
+ return false;
+ }
+ d->conflicts.resize(s.conflicts.size());
+ size_t i = 0;
+ for (const C2ParamFieldValues& sConflict : s.conflicts) {
+ auto &dConflict = d->conflicts[i++];
+ if (!objcpy(&dConflict, sConflict)) {
+ LOG(ERROR) << "Invalid C2SettingResult::conflicts["
+ << i - 1 << "].";
+ return false;
+ }
+ }
+ return true;
+}
+
+// SettingResult -> std::unique_ptr<C2SettingResult>
+template <typename SettingResult>
+bool objcpy(
+ std::unique_ptr<C2SettingResult> *d,
+ const SettingResult &s) {
+ typedef decltype((*d)->field) ParamField;
+ *d = std::unique_ptr<C2SettingResult>(new C2SettingResult {
+ .field = C2ParamFieldValues(C2ParamFieldBuilder<ParamField>()) });
+ if (!*d) {
+ LOG(ERROR) << "No memory for C2SettingResult.";
+ return false;
+ }
+
+ // failure
+ switch (s.failure) {
+ case SettingResult::Failure::BAD_TYPE:
+ (*d)->failure = C2SettingResult::BAD_TYPE;
+ break;
+ case SettingResult::Failure::BAD_PORT:
+ (*d)->failure = C2SettingResult::BAD_PORT;
+ break;
+ case SettingResult::Failure::BAD_INDEX:
+ (*d)->failure = C2SettingResult::BAD_INDEX;
+ break;
+ case SettingResult::Failure::READ_ONLY:
+ (*d)->failure = C2SettingResult::READ_ONLY;
+ break;
+ case SettingResult::Failure::MISMATCH:
+ (*d)->failure = C2SettingResult::MISMATCH;
+ break;
+ case SettingResult::Failure::BAD_VALUE:
+ (*d)->failure = C2SettingResult::BAD_VALUE;
+ break;
+ case SettingResult::Failure::CONFLICT:
+ (*d)->failure = C2SettingResult::CONFLICT;
+ break;
+ case SettingResult::Failure::UNSUPPORTED:
+ (*d)->failure = C2SettingResult::UNSUPPORTED;
+ break;
+ case SettingResult::Failure::INFO_BAD_VALUE:
+ (*d)->failure = C2SettingResult::INFO_BAD_VALUE;
+ break;
+ case SettingResult::Failure::INFO_CONFLICT:
+ (*d)->failure = C2SettingResult::INFO_CONFLICT;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized SettingResult::Failure "
+ << "with underlying value " << underlying_value(s.failure)
+ << ".";
+ (*d)->failure = static_cast<C2SettingResult::Failure>(s.failure);
+ }
+
+ // field
+ if (!objcpy(&(*d)->field, s.field)) {
+ LOG(ERROR) << "Invalid SettingResult::field.";
+ return false;
+ }
+
+ // conflicts
+ (*d)->conflicts.clear();
+ (*d)->conflicts.reserve(s.conflicts.size());
+ for (const auto& sConflict : s.conflicts) {
+ (*d)->conflicts.emplace_back(
+ C2ParamFieldValues{ C2ParamFieldBuilder<ParamField>(), nullptr });
+ if (!objcpy(&(*d)->conflicts.back(), sConflict)) {
+ LOG(ERROR) << "Invalid SettingResult::conflicts.";
+ return false;
+ }
+ }
+ return true;
+}
+
+// C2ParamDescriptor -> ParamDescriptor
+template <typename ParamDescriptor>
+bool objcpy(ParamDescriptor *d, const C2ParamDescriptor &s) {
+ d->index = static_cast<decltype(d->index)>(s.index());
+ d->attrib = static_cast<decltype(d->attrib)>(
+ _C2ParamInspector::GetAttrib(s));
+ d->name = s.name();
+ copyVector<uint32_t>(&d->dependencies, s.dependencies());
+ return true;
+}
+
+// ParamDescriptor -> C2ParamDescriptor
+template <typename ParamDescriptor>
+bool objcpy(std::shared_ptr<C2ParamDescriptor> *d, const ParamDescriptor &s) {
+ std::vector<C2Param::Index> dDependencies;
+ dDependencies.reserve(s.dependencies.size());
+ for (const auto& sDependency : s.dependencies) {
+ dDependencies.emplace_back(static_cast<uint32_t>(sDependency));
+ }
+ *d = std::make_shared<C2ParamDescriptor>(
+ C2Param::Index(static_cast<uint32_t>(s.index)),
+ static_cast<C2ParamDescriptor::attrib_t>(s.attrib),
+ C2String(s.name.c_str()),
+ std::move(dDependencies));
+ return true;
+}
+
+// C2StructDescriptor -> StructDescriptor
+template <typename StructDescriptor>
+bool objcpy(StructDescriptor *d, const C2StructDescriptor &s) {
+ d->type = static_cast<decltype(d->type)>(s.coreIndex().coreIndex());
+ d->fields.resize(s.numFields());
+ size_t i = 0;
+ for (const C2FieldDescriptor& sField : s) {
+ auto& dField = d->fields[i++];
+ SetFieldId(
+ &dField.fieldId,
+ _C2ParamInspector::GetOffset(sField),
+ _C2ParamInspector::GetSize(sField));
+ dField.type = static_cast<decltype(dField.type)>(sField.type());
+ dField.extent = static_cast<uint32_t>(sField.extent());
+ dField.name = static_cast<decltype(dField.name)>(sField.name());
+ const auto& sNamedValues = sField.namedValues();
+ dField.namedValues.resize(sNamedValues.size());
+ size_t j = 0;
+ for (const auto& sNamedValue : sNamedValues) {
+ auto& dNamedValue = dField.namedValues[j++];
+ dNamedValue.name = static_cast<decltype(dNamedValue.name)>(sNamedValue.first);
+ dNamedValue.value = static_cast<decltype(dNamedValue.value)>(
+ sNamedValue.second.u64);
+ }
+ }
+ return true;
+}
+
+// StructDescriptor -> C2StructDescriptor
+template <typename StructDescriptor>
+bool objcpy(std::unique_ptr<C2StructDescriptor> *d, const StructDescriptor &s) {
+ C2Param::CoreIndex dIndex = C2Param::CoreIndex(static_cast<uint32_t>(s.type));
+ std::vector<C2FieldDescriptor> dFields;
+ dFields.reserve(s.fields.size());
+ for (const auto &sField : s.fields) {
+ C2FieldDescriptor dField = {
+ static_cast<uint32_t>(sField.type),
+ static_cast<uint32_t>(sField.extent),
+ sField.name,
+ GetOffsetFromFieldId(sField.fieldId),
+ GetSizeFromFieldId(sField.fieldId) };
+ C2FieldDescriptor::NamedValuesType namedValues;
+ namedValues.reserve(sField.namedValues.size());
+ for (const auto& sNamedValue : sField.namedValues) {
+ namedValues.emplace_back(
+ sNamedValue.name,
+ C2Value::Primitive(static_cast<uint64_t>(sNamedValue.value)));
+ }
+ _C2ParamInspector::AddNamedValues(dField, std::move(namedValues));
+ dFields.emplace_back(dField);
+ }
+ *d = std::make_unique<C2StructDescriptor>(
+ _C2ParamInspector::CreateStructDescriptor(dIndex, std::move(dFields)));
+ return true;
+}
+
+constexpr size_t PARAMS_ALIGNMENT = 8; // 64-bit alignment
+static_assert(PARAMS_ALIGNMENT % alignof(C2Param) == 0, "C2Param alignment mismatch");
+static_assert(PARAMS_ALIGNMENT % alignof(C2Info) == 0, "C2Param alignment mismatch");
+static_assert(PARAMS_ALIGNMENT % alignof(C2Tuning) == 0, "C2Param alignment mismatch");
+
+template <typename Params>
+struct _ParamsBlobHelper { typedef Params BlobType; };
+
+template <typename Params>
+using ParamsBlobType = typename _ParamsBlobHelper<Params>::BlobType;
+
+template <typename Params>
+const ParamsBlobType<Params> &GetBlob(const Params ¶ms) {
+ return params;
+}
+
+template <typename Params>
+ParamsBlobType<Params> *GetBlob(Params *params) {
+ return params;
+}
+
+// Params -> std::vector<C2Param*>
+template <typename Params>
+bool parseParamsBlob(std::vector<C2Param*> *params, const Params ¶msBlob) {
+ // assuming blob is const here
+ const ParamsBlobType<Params> &blob = GetBlob(paramsBlob);
+ size_t size = blob.size();
+ size_t ix = 0;
+ size_t old_ix = 0;
+ const uint8_t *data = blob.data();
+ C2Param *p = nullptr;
+
+ do {
+ p = C2ParamUtils::ParseFirst(data + ix, size - ix);
+ if (p) {
+ params->emplace_back(p);
+ old_ix = ix;
+ ix += p->size();
+ ix = align(ix, PARAMS_ALIGNMENT);
+ if (ix <= old_ix || ix > size) {
+ android_errorWriteLog(0x534e4554, "238083570");
+ break;
+ }
+ }
+ } while (p);
+
+ if (ix != size) {
+ LOG(ERROR) << "parseParamsBlob -- inconsistent sizes.";
+ return false;
+ }
+ return true;
+}
+
+/**
+ * Concatenates a list of C2Params into a params blob. T is a container type
+ * whose member type is compatible with C2Param*.
+ *
+ * \param[out] blob target blob
+ * \param[in] params parameters to concatenate
+ * \retval C2_OK if the blob was successfully created
+ * \retval C2_BAD_VALUE if the blob was not successful created (this only
+ * happens if the parameters were not const)
+ */
+template <typename Params, typename T>
+bool _createParamsBlob(Params *paramsBlob, const T ¶ms) {
+ // assuming the parameter values are const
+ size_t size = 0;
+ for (const auto &p : params) {
+ if (!p) {
+ continue;
+ }
+ size += p->size();
+ size = align(size, PARAMS_ALIGNMENT);
+ }
+ ParamsBlobType<Params> *blob = GetBlob(paramsBlob);
+ blob->resize(size);
+ size_t ix = 0;
+ for (const auto &p : params) {
+ if (!p) {
+ continue;
+ }
+ // NEVER overwrite even if param values (e.g. size) changed
+ size_t paramSize = std::min(p->size(), size - ix);
+ std::copy(
+ reinterpret_cast<const uint8_t*>(&*p),
+ reinterpret_cast<const uint8_t*>(&*p) + paramSize,
+ &(*blob)[ix]);
+ ix += paramSize;
+ ix = align(ix, PARAMS_ALIGNMENT);
+ }
+ blob->resize(ix);
+ if (ix != size) {
+ LOG(ERROR) << "createParamsBlob -- inconsistent sizes.";
+ return false;
+ }
+ return true;
+}
+
+/**
+ * Parses a params blob and create a vector of new T objects that contain copies
+ * of the params in the blob. T is C2Param or its compatible derived class.
+ *
+ * \param[out] params the resulting vector
+ * \param[in] blob parameter blob to parse
+ * \retval C2_OK if the full blob was parsed and params was constructed
+ * \retval C2_BAD_VALUE otherwise
+ */
+template <typename Params, typename T>
+bool _copyParamsFromBlob(
+ std::vector<std::unique_ptr<T>>* params,
+ const Params ¶msBlob) {
+ const ParamsBlobType<Params> &blob = GetBlob(paramsBlob);
+ std::vector<C2Param*> paramPointers;
+ if (!parseParamsBlob(¶mPointers, blob)) {
+ LOG(ERROR) << "copyParamsFromBlob -- failed to parse.";
+ return false;
+ }
+
+ params->resize(paramPointers.size());
+ size_t i = 0;
+ for (C2Param* const& paramPointer : paramPointers) {
+ if (!paramPointer) {
+ LOG(ERROR) << "copyParamsFromBlob -- null paramPointer.";
+ return false;
+ }
+ (*params)[i++].reset(reinterpret_cast<T*>(
+ C2Param::Copy(*paramPointer).release()));
+ }
+ return true;
+}
+
+// Params -> update std::vector<std::unique_ptr<C2Param>>
+template <typename Params>
+bool updateParamsFromBlob(
+ const std::vector<C2Param*>& params,
+ const Params& paramsBlob) {
+ const ParamsBlobType<Params> &blob = GetBlob(paramsBlob);
+ std::unordered_map<uint32_t, C2Param*> index2param;
+ for (C2Param* const& param : params) {
+ if (!param) {
+ LOG(ERROR) << "updateParamsFromBlob -- null output param.";
+ return false;
+ }
+ if (index2param.find(param->index()) == index2param.end()) {
+ index2param.emplace(param->index(), param);
+ }
+ }
+
+ std::vector<C2Param*> paramPointers;
+ if (!parseParamsBlob(¶mPointers, blob)) {
+ LOG(ERROR) << "updateParamsFromBlob -- failed to parse.";
+ return false;
+ }
+
+ for (C2Param* const& paramPointer : paramPointers) {
+ if (!paramPointer) {
+ LOG(ERROR) << "updateParamsFromBlob -- null input param.";
+ return false;
+ }
+ decltype(index2param)::iterator i = index2param.find(
+ paramPointer->index());
+ if (i == index2param.end()) {
+ LOG(DEBUG) << "updateParamsFromBlob -- index "
+ << paramPointer->index() << " not found. Skipping...";
+ continue;
+ }
+ if (!i->second->updateFrom(*paramPointer)) {
+ LOG(ERROR) << "updateParamsFromBlob -- size mismatch: "
+ << params.size() << " vs " << paramPointer->size()
+ << " (index = " << i->first << ").";
+ return false;
+ }
+ }
+ return true;
+}
+
+} // namespace android
+
+#endif // CODEC2_COMMON_PARAM_TYPES_H
diff --git a/media/codec2/hal/hidl/1.0/utils/Android.bp b/media/codec2/hal/hidl/1.0/utils/Android.bp
index db7874d..2933940 100644
--- a/media/codec2/hal/hidl/1.0/utils/Android.bp
+++ b/media/codec2/hal/hidl/1.0/utils/Android.bp
@@ -19,6 +19,7 @@
],
header_libs: [
+ "libcodec2_hal_common",
"libcodec2_internal", // private
],
@@ -77,8 +78,9 @@
header_libs: [
"libbinder_headers",
- "libsystem_headers",
+ "libcodec2_hal_common",
"libcodec2_internal", // private
+ "libsystem_headers",
],
shared_libs: [
diff --git a/media/codec2/hal/hidl/1.0/utils/types.cpp b/media/codec2/hal/hidl/1.0/utils/types.cpp
index 319ba62..e17aad4 100644
--- a/media/codec2/hal/hidl/1.0/utils/types.cpp
+++ b/media/codec2/hal/hidl/1.0/utils/types.cpp
@@ -18,8 +18,8 @@
#define LOG_TAG "Codec2-types"
#include <android-base/logging.h>
+#include <codec2/common/ParamTypes.h>
#include <codec2/hidl/1.0/types.h>
-#include <media/stagefright/foundation/AUtils.h>
#include <C2AllocatorIon.h>
#include <C2AllocatorGralloc.h>
@@ -27,108 +27,20 @@
#include <C2Buffer.h>
#include <C2Component.h>
#include <C2FenceFactory.h>
-#include <C2Param.h>
-#include <C2ParamInternal.h>
#include <C2PlatformSupport.h>
#include <C2Work.h>
-#include <util/C2ParamUtils.h>
-
-#include <algorithm>
-#include <functional>
-#include <iomanip>
-#include <unordered_map>
namespace android {
-namespace hardware {
-namespace media {
-namespace c2 {
-namespace V1_0 {
-namespace utils {
-using ::android::hardware::Return;
-using ::android::hardware::media::bufferpool::BufferPoolData;
-using ::android::hardware::media::bufferpool::V2_0::BufferStatusMessage;
-using ::android::hardware::media::bufferpool::V2_0::ResultStatus;
-using ::android::hardware::media::bufferpool::V2_0::implementation::
- ClientManager;
-using ::android::hardware::media::bufferpool::V2_0::implementation::
- TransactionId;
-
-const char* asString(Status status, const char* def) {
- return asString(static_cast<c2_status_t>(status), def);
-}
-
-namespace /* unnamed */ {
-
-template <typename EnumClass>
-typename std::underlying_type<EnumClass>::type underlying_value(
- EnumClass x) {
- return static_cast<typename std::underlying_type<EnumClass>::type>(x);
-}
-
-template <typename Common, typename DstVector, typename SrcVector>
-void copyVector(DstVector* d, const SrcVector& s) {
- static_assert(sizeof(Common) == sizeof(decltype((*d)[0])),
- "DstVector's component size does not match Common");
- static_assert(sizeof(Common) == sizeof(decltype(s[0])),
- "SrcVector's component size does not match Common");
- d->resize(s.size());
- std::copy(
- reinterpret_cast<const Common*>(&s[0]),
- reinterpret_cast<const Common*>(&s[0] + s.size()),
- reinterpret_cast<Common*>(&(*d)[0]));
-}
-
-// C2ParamField -> ParamField
-bool objcpy(ParamField *d, const C2ParamField &s) {
- d->index = static_cast<ParamIndex>(_C2ParamInspector::GetIndex(s));
- d->fieldId.offset = static_cast<uint32_t>(_C2ParamInspector::GetOffset(s));
- d->fieldId.size = static_cast<uint32_t>(_C2ParamInspector::GetSize(s));
- return true;
-}
-
-struct C2ParamFieldBuilder : public C2ParamField {
- C2ParamFieldBuilder() : C2ParamField(
- static_cast<C2Param::Index>(static_cast<uint32_t>(0)), 0, 0) {
- }
- // ParamField -> C2ParamField
- C2ParamFieldBuilder(const ParamField& s) : C2ParamField(
- static_cast<C2Param::Index>(static_cast<uint32_t>(s.index)),
- static_cast<uint32_t>(s.fieldId.offset),
- static_cast<uint32_t>(s.fieldId.size)) {
- }
-};
-
-// C2WorkOrdinalStruct -> WorkOrdinal
-bool objcpy(WorkOrdinal *d, const C2WorkOrdinalStruct &s) {
- d->frameIndex = static_cast<uint64_t>(s.frameIndex.peeku());
- d->timestampUs = static_cast<uint64_t>(s.timestamp.peeku());
- d->customOrdinal = static_cast<uint64_t>(s.customOrdinal.peeku());
- return true;
-}
-
-// WorkOrdinal -> C2WorkOrdinalStruct
-bool objcpy(C2WorkOrdinalStruct *d, const WorkOrdinal &s) {
- d->frameIndex = c2_cntr64_t(s.frameIndex);
- d->timestamp = c2_cntr64_t(s.timestampUs);
- d->customOrdinal = c2_cntr64_t(s.customOrdinal);
- return true;
-}
-
-// C2FieldSupportedValues::range's type -> ValueRange
-bool objcpy(
- ValueRange* d,
- const decltype(C2FieldSupportedValues::range)& s) {
- d->min = static_cast<PrimitiveValue>(s.min.u64);
- d->max = static_cast<PrimitiveValue>(s.max.u64);
- d->step = static_cast<PrimitiveValue>(s.step.u64);
- d->num = static_cast<PrimitiveValue>(s.num.u64);
- d->denom = static_cast<PrimitiveValue>(s.denom.u64);
- return true;
-}
+using hardware::media::c2::V1_0::FieldSupportedValues;
+using hardware::media::c2::V1_0::PrimitiveValue;
+using hardware::media::c2::V1_0::ValueRange;
+using hardware::hidl_vec;
// C2FieldSupportedValues -> FieldSupportedValues
-bool objcpy(FieldSupportedValues *d, const C2FieldSupportedValues &s) {
+template<>
+bool objcpy(
+ FieldSupportedValues *d, const C2FieldSupportedValues &s) {
switch (s.type) {
case C2FieldSupportedValues::EMPTY: {
d->empty(::android::hidl::safe_union::V1_0::Monostate{});
@@ -165,20 +77,10 @@
return true;
}
-// ValueRange -> C2FieldSupportedValues::range's type
-bool objcpy(
- decltype(C2FieldSupportedValues::range)* d,
- const ValueRange& s) {
- d->min.u64 = static_cast<uint64_t>(s.min);
- d->max.u64 = static_cast<uint64_t>(s.max);
- d->step.u64 = static_cast<uint64_t>(s.step);
- d->num.u64 = static_cast<uint64_t>(s.num);
- d->denom.u64 = static_cast<uint64_t>(s.denom);
- return true;
-}
-
// FieldSupportedValues -> C2FieldSupportedValues
-bool objcpy(C2FieldSupportedValues *d, const FieldSupportedValues &s) {
+template<>
+bool objcpy(
+ C2FieldSupportedValues *d, const FieldSupportedValues &s) {
switch (s.getDiscriminator()) {
case FieldSupportedValues::hidl_discriminator::empty: {
d->type = C2FieldSupportedValues::EMPTY;
@@ -210,60 +112,43 @@
return true;
}
-} // unnamed namespace
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using ::android::hardware::media::bufferpool::BufferPoolData;
+using ::android::hardware::media::bufferpool::V2_0::BufferStatusMessage;
+using ::android::hardware::media::bufferpool::V2_0::ResultStatus;
+using ::android::hardware::media::bufferpool::V2_0::implementation::
+ ClientManager;
+using ::android::hardware::media::bufferpool::V2_0::implementation::
+ TransactionId;
+
+const char* asString(Status status, const char* def) {
+ return asString(static_cast<c2_status_t>(status), def);
+}
// C2FieldSupportedValuesQuery -> FieldSupportedValuesQuery
bool objcpy(
FieldSupportedValuesQuery* d,
const C2FieldSupportedValuesQuery& s) {
- if (!objcpy(&d->field, s.field())) {
- LOG(ERROR) << "Invalid C2FieldSupportedValuesQuery::field.";
- return false;
- }
- switch (s.type()) {
- case C2FieldSupportedValuesQuery::POSSIBLE:
- d->type = FieldSupportedValuesQuery::Type::POSSIBLE;
- break;
- case C2FieldSupportedValuesQuery::CURRENT:
- d->type = FieldSupportedValuesQuery::Type::CURRENT;
- break;
- default:
- LOG(DEBUG) << "Unrecognized C2FieldSupportedValuesQuery::type_t "
- << "with underlying value " << underlying_value(s.type())
- << ".";
- d->type = static_cast<FieldSupportedValuesQuery::Type>(s.type());
- }
- return true;
+ return ::android::objcpy(d, nullptr, s);
}
// FieldSupportedValuesQuery -> C2FieldSupportedValuesQuery
bool objcpy(
C2FieldSupportedValuesQuery* d,
const FieldSupportedValuesQuery& s) {
- C2FieldSupportedValuesQuery::type_t dType;
- switch (s.type) {
- case FieldSupportedValuesQuery::Type::POSSIBLE:
- dType = C2FieldSupportedValuesQuery::POSSIBLE;
- break;
- case FieldSupportedValuesQuery::Type::CURRENT:
- dType = C2FieldSupportedValuesQuery::CURRENT;
- break;
- default:
- LOG(DEBUG) << "Unrecognized FieldSupportedValuesQuery::Type "
- << "with underlying value " << underlying_value(s.type)
- << ".";
- dType = static_cast<C2FieldSupportedValuesQuery::type_t>(s.type);
- }
- *d = C2FieldSupportedValuesQuery(C2ParamFieldBuilder(s.field), dType);
- return true;
+ return ::android::objcpy(d, s);
}
// C2FieldSupportedValuesQuery -> FieldSupportedValuesQueryResult
bool objcpy(
FieldSupportedValuesQueryResult* d,
const C2FieldSupportedValuesQuery& s) {
- d->status = static_cast<Status>(s.status);
- return objcpy(&d->values, s.values);
+ return ::android::objcpy(nullptr, d, s);
}
// FieldSupportedValuesQuery, FieldSupportedValuesQueryResult ->
@@ -272,372 +157,51 @@
C2FieldSupportedValuesQuery* d,
const FieldSupportedValuesQuery& sq,
const FieldSupportedValuesQueryResult& sr) {
- if (!objcpy(d, sq)) {
- LOG(ERROR) << "Invalid FieldSupportedValuesQuery.";
- return false;
- }
- d->status = static_cast<c2_status_t>(sr.status);
- if (!objcpy(&d->values, sr.values)) {
- LOG(ERROR) << "Invalid FieldSupportedValuesQueryResult::values.";
- return false;
- }
- return true;
+ return ::android::objcpy(d, sq, sr);
}
// C2Component::Traits -> IComponentStore::ComponentTraits
bool objcpy(
IComponentStore::ComponentTraits *d,
const C2Component::Traits &s) {
- d->name = s.name;
-
- switch (s.domain) {
- case C2Component::DOMAIN_VIDEO:
- d->domain = IComponentStore::ComponentTraits::Domain::VIDEO;
- break;
- case C2Component::DOMAIN_AUDIO:
- d->domain = IComponentStore::ComponentTraits::Domain::AUDIO;
- break;
- case C2Component::DOMAIN_IMAGE:
- d->domain = IComponentStore::ComponentTraits::Domain::IMAGE;
- break;
- case C2Component::DOMAIN_OTHER:
- d->domain = IComponentStore::ComponentTraits::Domain::OTHER;
- break;
- default:
- LOG(DEBUG) << "Unrecognized C2Component::domain_t "
- << "with underlying value " << underlying_value(s.domain)
- << ".";
- d->domain = static_cast<IComponentStore::ComponentTraits::Domain>(
- s.domain);
- }
-
- switch (s.kind) {
- case C2Component::KIND_DECODER:
- d->kind = IComponentStore::ComponentTraits::Kind::DECODER;
- break;
- case C2Component::KIND_ENCODER:
- d->kind = IComponentStore::ComponentTraits::Kind::ENCODER;
- break;
- case C2Component::KIND_OTHER:
- d->kind = IComponentStore::ComponentTraits::Kind::OTHER;
- break;
- default:
- LOG(DEBUG) << "Unrecognized C2Component::kind_t "
- << "with underlying value " << underlying_value(s.kind)
- << ".";
- d->kind = static_cast<IComponentStore::ComponentTraits::Kind>(
- s.kind);
- }
-
- d->rank = static_cast<uint32_t>(s.rank);
-
- d->mediaType = s.mediaType;
-
- d->aliases.resize(s.aliases.size());
- for (size_t ix = s.aliases.size(); ix > 0; ) {
- --ix;
- d->aliases[ix] = s.aliases[ix];
- }
- return true;
+ return ::android::objcpy(d, s);
}
// ComponentTraits -> C2Component::Traits, std::unique_ptr<std::vector<std::string>>
bool objcpy(
C2Component::Traits* d,
const IComponentStore::ComponentTraits& s) {
- d->name = s.name.c_str();
-
- switch (s.domain) {
- case IComponentStore::ComponentTraits::Domain::VIDEO:
- d->domain = C2Component::DOMAIN_VIDEO;
- break;
- case IComponentStore::ComponentTraits::Domain::AUDIO:
- d->domain = C2Component::DOMAIN_AUDIO;
- break;
- case IComponentStore::ComponentTraits::Domain::IMAGE:
- d->domain = C2Component::DOMAIN_IMAGE;
- break;
- case IComponentStore::ComponentTraits::Domain::OTHER:
- d->domain = C2Component::DOMAIN_OTHER;
- break;
- default:
- LOG(DEBUG) << "Unrecognized ComponentTraits::Domain "
- << "with underlying value " << underlying_value(s.domain)
- << ".";
- d->domain = static_cast<C2Component::domain_t>(s.domain);
- }
-
- switch (s.kind) {
- case IComponentStore::ComponentTraits::Kind::DECODER:
- d->kind = C2Component::KIND_DECODER;
- break;
- case IComponentStore::ComponentTraits::Kind::ENCODER:
- d->kind = C2Component::KIND_ENCODER;
- break;
- case IComponentStore::ComponentTraits::Kind::OTHER:
- d->kind = C2Component::KIND_OTHER;
- break;
- default:
- LOG(DEBUG) << "Unrecognized ComponentTraits::Kind "
- << "with underlying value " << underlying_value(s.kind)
- << ".";
- d->kind = static_cast<C2Component::kind_t>(s.kind);
- }
-
- d->rank = static_cast<C2Component::rank_t>(s.rank);
- d->mediaType = s.mediaType.c_str();
- d->aliases.resize(s.aliases.size());
- for (size_t i = 0; i < s.aliases.size(); ++i) {
- d->aliases[i] = s.aliases[i];
- }
- return true;
+ return ::android::objcpy(d, s);
}
-namespace /* unnamed */ {
-
-// C2ParamFieldValues -> ParamFieldValues
-bool objcpy(ParamFieldValues *d, const C2ParamFieldValues &s) {
- if (!objcpy(&d->paramOrField, s.paramOrField)) {
- LOG(ERROR) << "Invalid C2ParamFieldValues::paramOrField.";
- return false;
- }
- if (s.values) {
- d->values.resize(1);
- if (!objcpy(&d->values[0], *s.values)) {
- LOG(ERROR) << "Invalid C2ParamFieldValues::values.";
- return false;
- }
- return true;
- }
- d->values.resize(0);
- return true;
-}
-
-// ParamFieldValues -> C2ParamFieldValues
-bool objcpy(C2ParamFieldValues *d, const ParamFieldValues &s) {
- d->paramOrField = C2ParamFieldBuilder(s.paramOrField);
- if (s.values.size() == 1) {
- d->values = std::make_unique<C2FieldSupportedValues>();
- if (!objcpy(d->values.get(), s.values[0])) {
- LOG(ERROR) << "Invalid ParamFieldValues::values.";
- return false;
- }
- return true;
- } else if (s.values.size() == 0) {
- d->values.reset();
- return true;
- }
- LOG(ERROR) << "Invalid ParamFieldValues: "
- "Two or more FieldSupportedValues objects exist in "
- "ParamFieldValues. "
- "Only zero or one is allowed.";
- return false;
-}
-
-} // unnamed namespace
-
// C2SettingResult -> SettingResult
bool objcpy(SettingResult *d, const C2SettingResult &s) {
- switch (s.failure) {
- case C2SettingResult::BAD_TYPE:
- d->failure = SettingResult::Failure::BAD_TYPE;
- break;
- case C2SettingResult::BAD_PORT:
- d->failure = SettingResult::Failure::BAD_PORT;
- break;
- case C2SettingResult::BAD_INDEX:
- d->failure = SettingResult::Failure::BAD_INDEX;
- break;
- case C2SettingResult::READ_ONLY:
- d->failure = SettingResult::Failure::READ_ONLY;
- break;
- case C2SettingResult::MISMATCH:
- d->failure = SettingResult::Failure::MISMATCH;
- break;
- case C2SettingResult::BAD_VALUE:
- d->failure = SettingResult::Failure::BAD_VALUE;
- break;
- case C2SettingResult::CONFLICT:
- d->failure = SettingResult::Failure::CONFLICT;
- break;
- case C2SettingResult::UNSUPPORTED:
- d->failure = SettingResult::Failure::UNSUPPORTED;
- break;
- case C2SettingResult::INFO_BAD_VALUE:
- d->failure = SettingResult::Failure::INFO_BAD_VALUE;
- break;
- case C2SettingResult::INFO_CONFLICT:
- d->failure = SettingResult::Failure::INFO_CONFLICT;
- break;
- default:
- LOG(DEBUG) << "Unrecognized C2SettingResult::Failure "
- << "with underlying value " << underlying_value(s.failure)
- << ".";
- d->failure = static_cast<SettingResult::Failure>(s.failure);
- }
- if (!objcpy(&d->field, s.field)) {
- LOG(ERROR) << "Invalid C2SettingResult::field.";
- return false;
- }
- d->conflicts.resize(s.conflicts.size());
- size_t i = 0;
- for (const C2ParamFieldValues& sConflict : s.conflicts) {
- ParamFieldValues &dConflict = d->conflicts[i++];
- if (!objcpy(&dConflict, sConflict)) {
- LOG(ERROR) << "Invalid C2SettingResult::conflicts["
- << i - 1 << "].";
- return false;
- }
- }
- return true;
+ return ::android::objcpy(d, s);
}
// SettingResult -> std::unique_ptr<C2SettingResult>
bool objcpy(std::unique_ptr<C2SettingResult> *d, const SettingResult &s) {
- *d = std::unique_ptr<C2SettingResult>(new C2SettingResult {
- .field = C2ParamFieldValues(C2ParamFieldBuilder()) });
- if (!*d) {
- LOG(ERROR) << "No memory for C2SettingResult.";
- return false;
- }
-
- // failure
- switch (s.failure) {
- case SettingResult::Failure::BAD_TYPE:
- (*d)->failure = C2SettingResult::BAD_TYPE;
- break;
- case SettingResult::Failure::BAD_PORT:
- (*d)->failure = C2SettingResult::BAD_PORT;
- break;
- case SettingResult::Failure::BAD_INDEX:
- (*d)->failure = C2SettingResult::BAD_INDEX;
- break;
- case SettingResult::Failure::READ_ONLY:
- (*d)->failure = C2SettingResult::READ_ONLY;
- break;
- case SettingResult::Failure::MISMATCH:
- (*d)->failure = C2SettingResult::MISMATCH;
- break;
- case SettingResult::Failure::BAD_VALUE:
- (*d)->failure = C2SettingResult::BAD_VALUE;
- break;
- case SettingResult::Failure::CONFLICT:
- (*d)->failure = C2SettingResult::CONFLICT;
- break;
- case SettingResult::Failure::UNSUPPORTED:
- (*d)->failure = C2SettingResult::UNSUPPORTED;
- break;
- case SettingResult::Failure::INFO_BAD_VALUE:
- (*d)->failure = C2SettingResult::INFO_BAD_VALUE;
- break;
- case SettingResult::Failure::INFO_CONFLICT:
- (*d)->failure = C2SettingResult::INFO_CONFLICT;
- break;
- default:
- LOG(DEBUG) << "Unrecognized SettingResult::Failure "
- << "with underlying value " << underlying_value(s.failure)
- << ".";
- (*d)->failure = static_cast<C2SettingResult::Failure>(s.failure);
- }
-
- // field
- if (!objcpy(&(*d)->field, s.field)) {
- LOG(ERROR) << "Invalid SettingResult::field.";
- return false;
- }
-
- // conflicts
- (*d)->conflicts.clear();
- (*d)->conflicts.reserve(s.conflicts.size());
- for (const ParamFieldValues& sConflict : s.conflicts) {
- (*d)->conflicts.emplace_back(
- C2ParamFieldValues{ C2ParamFieldBuilder(), nullptr });
- if (!objcpy(&(*d)->conflicts.back(), sConflict)) {
- LOG(ERROR) << "Invalid SettingResult::conflicts.";
- return false;
- }
- }
- return true;
+ return ::android::objcpy(d, s);
}
// C2ParamDescriptor -> ParamDescriptor
bool objcpy(ParamDescriptor *d, const C2ParamDescriptor &s) {
- d->index = static_cast<ParamIndex>(s.index());
- d->attrib = static_cast<hidl_bitfield<ParamDescriptor::Attrib>>(
- _C2ParamInspector::GetAttrib(s));
- d->name = s.name();
- copyVector<uint32_t>(&d->dependencies, s.dependencies());
- return true;
+ return ::android::objcpy(d, s);
}
// ParamDescriptor -> C2ParamDescriptor
bool objcpy(std::shared_ptr<C2ParamDescriptor> *d, const ParamDescriptor &s) {
- std::vector<C2Param::Index> dDependencies;
- dDependencies.reserve(s.dependencies.size());
- for (const ParamIndex& sDependency : s.dependencies) {
- dDependencies.emplace_back(static_cast<uint32_t>(sDependency));
- }
- *d = std::make_shared<C2ParamDescriptor>(
- C2Param::Index(static_cast<uint32_t>(s.index)),
- static_cast<C2ParamDescriptor::attrib_t>(s.attrib),
- C2String(s.name.c_str()),
- std::move(dDependencies));
- return true;
+ return ::android::objcpy(d, s);
}
// C2StructDescriptor -> StructDescriptor
bool objcpy(StructDescriptor *d, const C2StructDescriptor &s) {
- d->type = static_cast<ParamIndex>(s.coreIndex().coreIndex());
- d->fields.resize(s.numFields());
- size_t i = 0;
- for (const auto& sField : s) {
- FieldDescriptor& dField = d->fields[i++];
- dField.fieldId.offset = static_cast<uint32_t>(
- _C2ParamInspector::GetOffset(sField));
- dField.fieldId.size = static_cast<uint32_t>(
- _C2ParamInspector::GetSize(sField));
- dField.type = static_cast<hidl_bitfield<FieldDescriptor::Type>>(
- sField.type());
- dField.extent = static_cast<uint32_t>(sField.extent());
- dField.name = static_cast<hidl_string>(sField.name());
- const auto& sNamedValues = sField.namedValues();
- dField.namedValues.resize(sNamedValues.size());
- size_t j = 0;
- for (const auto& sNamedValue : sNamedValues) {
- FieldDescriptor::NamedValue& dNamedValue = dField.namedValues[j++];
- dNamedValue.name = static_cast<hidl_string>(sNamedValue.first);
- dNamedValue.value = static_cast<PrimitiveValue>(
- sNamedValue.second.u64);
- }
- }
- return true;
+ return ::android::objcpy(d, s);
}
// StructDescriptor -> C2StructDescriptor
bool objcpy(std::unique_ptr<C2StructDescriptor> *d, const StructDescriptor &s) {
- C2Param::CoreIndex dIndex = C2Param::CoreIndex(static_cast<uint32_t>(s.type));
- std::vector<C2FieldDescriptor> dFields;
- dFields.reserve(s.fields.size());
- for (const auto &sField : s.fields) {
- C2FieldDescriptor dField = {
- static_cast<uint32_t>(sField.type),
- sField.extent,
- sField.name,
- sField.fieldId.offset,
- sField.fieldId.size };
- C2FieldDescriptor::NamedValuesType namedValues;
- namedValues.reserve(sField.namedValues.size());
- for (const auto& sNamedValue : sField.namedValues) {
- namedValues.emplace_back(
- sNamedValue.name,
- C2Value::Primitive(static_cast<uint64_t>(sNamedValue.value)));
- }
- _C2ParamInspector::AddNamedValues(dField, std::move(namedValues));
- dFields.emplace_back(dField);
- }
- *d = std::make_unique<C2StructDescriptor>(
- _C2ParamInspector::CreateStructDescriptor(dIndex, std::move(dFields)));
- return true;
+ return ::android::objcpy(d, s);
}
namespace /* unnamed */ {
@@ -666,7 +230,6 @@
// This does not clone the handle.
dBaseBlock.nativeBlock(
reinterpret_cast<const native_handle_t*>(handle));
-
}
return true;
}
@@ -908,7 +471,7 @@
std::list<BaseBlock>* baseBlocks,
std::map<const void*, uint32_t>* baseBlockIndices) {
d->flags = static_cast<hidl_bitfield<FrameData::Flags>>(s.flags);
- if (!objcpy(&d->ordinal, s.ordinal)) {
+ if (!::android::objcpy(&d->ordinal, s.ordinal)) {
LOG(ERROR) << "Invalid C2FrameData::ordinal.";
return false;
}
@@ -1398,7 +961,7 @@
bool objcpy(C2FrameData* d, const FrameData& s,
const std::vector<C2BaseBlock>& baseBlocks) {
d->flags = static_cast<C2FrameData::flags_t>(s.flags);
- if (!objcpy(&d->ordinal, s.ordinal)) {
+ if (!::android::objcpy(&d->ordinal, s.ordinal)) {
LOG(ERROR) << "Invalid FrameData::ordinal.";
return false;
}
@@ -1603,212 +1166,65 @@
return true;
}
-constexpr size_t PARAMS_ALIGNMENT = 8; // 64-bit alignment
-static_assert(PARAMS_ALIGNMENT % alignof(C2Param) == 0, "C2Param alignment mismatch");
-static_assert(PARAMS_ALIGNMENT % alignof(C2Info) == 0, "C2Param alignment mismatch");
-static_assert(PARAMS_ALIGNMENT % alignof(C2Tuning) == 0, "C2Param alignment mismatch");
-
// Params -> std::vector<C2Param*>
bool parseParamsBlob(std::vector<C2Param*> *params, const hidl_vec<uint8_t> &blob) {
- // assuming blob is const here
- size_t size = blob.size();
- size_t ix = 0;
- size_t old_ix = 0;
- const uint8_t *data = blob.data();
- C2Param *p = nullptr;
-
- do {
- p = C2ParamUtils::ParseFirst(data + ix, size - ix);
- if (p) {
- params->emplace_back(p);
- old_ix = ix;
- ix += p->size();
- ix = align(ix, PARAMS_ALIGNMENT);
- if (ix <= old_ix || ix > size) {
- android_errorWriteLog(0x534e4554, "238083570");
- break;
- }
- }
- } while (p);
-
- if (ix != size) {
- LOG(ERROR) << "parseParamsBlob -- inconsistent sizes.";
- return false;
- }
- return true;
+ return ::android::parseParamsBlob(params, blob);
}
-namespace /* unnamed */ {
-
-/**
- * Concatenates a list of C2Params into a params blob. T is a container type
- * whose member type is compatible with C2Param*.
- *
- * \param[out] blob target blob
- * \param[in] params parameters to concatenate
- * \retval C2_OK if the blob was successfully created
- * \retval C2_BAD_VALUE if the blob was not successful created (this only
- * happens if the parameters were not const)
- */
-template <typename T>
-bool _createParamsBlob(hidl_vec<uint8_t> *blob, const T ¶ms) {
- // assuming the parameter values are const
- size_t size = 0;
- for (const auto &p : params) {
- if (!p) {
- continue;
- }
- size += p->size();
- size = align(size, PARAMS_ALIGNMENT);
- }
- blob->resize(size);
- size_t ix = 0;
- for (const auto &p : params) {
- if (!p) {
- continue;
- }
- // NEVER overwrite even if param values (e.g. size) changed
- size_t paramSize = std::min(p->size(), size - ix);
- std::copy(
- reinterpret_cast<const uint8_t*>(&*p),
- reinterpret_cast<const uint8_t*>(&*p) + paramSize,
- &(*blob)[ix]);
- ix += paramSize;
- ix = align(ix, PARAMS_ALIGNMENT);
- }
- blob->resize(ix);
- if (ix != size) {
- LOG(ERROR) << "createParamsBlob -- inconsistent sizes.";
- return false;
- }
- return true;
-}
-
-/**
- * Parses a params blob and create a vector of new T objects that contain copies
- * of the params in the blob. T is C2Param or its compatible derived class.
- *
- * \param[out] params the resulting vector
- * \param[in] blob parameter blob to parse
- * \retval C2_OK if the full blob was parsed and params was constructed
- * \retval C2_BAD_VALUE otherwise
- */
-template <typename T>
-bool _copyParamsFromBlob(
- std::vector<std::unique_ptr<T>>* params,
- Params blob) {
-
- std::vector<C2Param*> paramPointers;
- if (!parseParamsBlob(¶mPointers, blob)) {
- LOG(ERROR) << "copyParamsFromBlob -- failed to parse.";
- return false;
- }
-
- params->resize(paramPointers.size());
- size_t i = 0;
- for (C2Param* const& paramPointer : paramPointers) {
- if (!paramPointer) {
- LOG(ERROR) << "copyParamsFromBlob -- null paramPointer.";
- return false;
- }
- (*params)[i++].reset(reinterpret_cast<T*>(
- C2Param::Copy(*paramPointer).release()));
- }
- return true;
-}
-
-} // unnamed namespace
-
// std::vector<const C2Param*> -> Params
bool createParamsBlob(
hidl_vec<uint8_t> *blob,
const std::vector<const C2Param*> ¶ms) {
- return _createParamsBlob(blob, params);
+ return ::android::_createParamsBlob(blob, params);
}
// std::vector<C2Param*> -> Params
bool createParamsBlob(
hidl_vec<uint8_t> *blob,
const std::vector<C2Param*> ¶ms) {
- return _createParamsBlob(blob, params);
+ return ::android::_createParamsBlob(blob, params);
}
// std::vector<std::unique_ptr<C2Param>> -> Params
bool createParamsBlob(
hidl_vec<uint8_t> *blob,
const std::vector<std::unique_ptr<C2Param>> ¶ms) {
- return _createParamsBlob(blob, params);
+ return ::android::_createParamsBlob(blob, params);
}
// std::vector<std::unique_ptr<C2Tuning>> -> Params
bool createParamsBlob(
hidl_vec<uint8_t> *blob,
const std::vector<std::unique_ptr<C2Tuning>> ¶ms) {
- return _createParamsBlob(blob, params);
+ return ::android::_createParamsBlob(blob, params);
}
// std::vector<std::shared_ptr<const C2Info>> -> Params
bool createParamsBlob(
hidl_vec<uint8_t> *blob,
const std::vector<std::shared_ptr<const C2Info>> ¶ms) {
- return _createParamsBlob(blob, params);
+ return ::android::_createParamsBlob(blob, params);
}
// Params -> std::vector<std::unique_ptr<C2Param>>
bool copyParamsFromBlob(
std::vector<std::unique_ptr<C2Param>>* params,
Params blob) {
- return _copyParamsFromBlob(params, blob);
+ return ::android::_copyParamsFromBlob(params, blob);
}
// Params -> std::vector<std::unique_ptr<C2Tuning>>
bool copyParamsFromBlob(
std::vector<std::unique_ptr<C2Tuning>>* params,
Params blob) {
- return _copyParamsFromBlob(params, blob);
+ return ::android::_copyParamsFromBlob(params, blob);
}
// Params -> update std::vector<std::unique_ptr<C2Param>>
bool updateParamsFromBlob(
const std::vector<C2Param*>& params,
const Params& blob) {
- std::unordered_map<uint32_t, C2Param*> index2param;
- for (C2Param* const& param : params) {
- if (!param) {
- LOG(ERROR) << "updateParamsFromBlob -- null output param.";
- return false;
- }
- if (index2param.find(param->index()) == index2param.end()) {
- index2param.emplace(param->index(), param);
- }
- }
-
- std::vector<C2Param*> paramPointers;
- if (!parseParamsBlob(¶mPointers, blob)) {
- LOG(ERROR) << "updateParamsFromBlob -- failed to parse.";
- return false;
- }
-
- for (C2Param* const& paramPointer : paramPointers) {
- if (!paramPointer) {
- LOG(ERROR) << "updateParamsFromBlob -- null input param.";
- return false;
- }
- decltype(index2param)::iterator i = index2param.find(
- paramPointer->index());
- if (i == index2param.end()) {
- LOG(DEBUG) << "updateParamsFromBlob -- index "
- << paramPointer->index() << " not found. Skipping...";
- continue;
- }
- if (!i->second->updateFrom(*paramPointer)) {
- LOG(ERROR) << "updateParamsFromBlob -- size mismatch: "
- << params.size() << " vs " << paramPointer->size()
- << " (index = " << i->first << ").";
- return false;
- }
- }
- return true;
+ return ::android::updateParamsFromBlob(params, blob);
}
// Convert BufferPool ResultStatus to c2_status_t.
diff --git a/media/libaaudio/include/aaudio/AAudio.h b/media/libaaudio/include/aaudio/AAudio.h
index 7648c76..74f7e6b 100644
--- a/media/libaaudio/include/aaudio/AAudio.h
+++ b/media/libaaudio/include/aaudio/AAudio.h
@@ -623,6 +623,11 @@
* (e.g. a USB audio interface, a DAC connected to headphones) to
* specify allowable configurations of a particular device.
*
+ * Channel masks are for input only, output only, or both input and output.
+ * These channel masks are different than those defined in AudioFormat.java.
+ * If an app gets a channel mask from Java API and wants to use it in AAudio,
+ * conversion should be done by the app.
+ *
* Added in API level 32.
*/
enum {
@@ -630,10 +635,6 @@
* Invalid channel mask
*/
AAUDIO_CHANNEL_INVALID = -1,
-
- /**
- * Output audio channel mask
- */
AAUDIO_CHANNEL_FRONT_LEFT = 1 << 0,
AAUDIO_CHANNEL_FRONT_RIGHT = 1 << 1,
AAUDIO_CHANNEL_FRONT_CENTER = 1 << 2,
@@ -661,62 +662,112 @@
AAUDIO_CHANNEL_FRONT_WIDE_LEFT = 1 << 24,
AAUDIO_CHANNEL_FRONT_WIDE_RIGHT = 1 << 25,
+ /**
+ * Supported for Input and Output
+ */
AAUDIO_CHANNEL_MONO = AAUDIO_CHANNEL_FRONT_LEFT,
+ /**
+ * Supported for Input and Output
+ */
AAUDIO_CHANNEL_STEREO = AAUDIO_CHANNEL_FRONT_LEFT |
AAUDIO_CHANNEL_FRONT_RIGHT,
+ /**
+ * Supported for only Output
+ */
AAUDIO_CHANNEL_2POINT1 = AAUDIO_CHANNEL_FRONT_LEFT |
AAUDIO_CHANNEL_FRONT_RIGHT |
AAUDIO_CHANNEL_LOW_FREQUENCY,
+ /**
+ * Supported for only Output
+ */
AAUDIO_CHANNEL_TRI = AAUDIO_CHANNEL_FRONT_LEFT |
AAUDIO_CHANNEL_FRONT_RIGHT |
AAUDIO_CHANNEL_FRONT_CENTER,
+ /**
+ * Supported for only Output
+ */
AAUDIO_CHANNEL_TRI_BACK = AAUDIO_CHANNEL_FRONT_LEFT |
AAUDIO_CHANNEL_FRONT_RIGHT |
AAUDIO_CHANNEL_BACK_CENTER,
+ /**
+ * Supported for only Output
+ */
AAUDIO_CHANNEL_3POINT1 = AAUDIO_CHANNEL_FRONT_LEFT |
AAUDIO_CHANNEL_FRONT_RIGHT |
AAUDIO_CHANNEL_FRONT_CENTER |
AAUDIO_CHANNEL_LOW_FREQUENCY,
+ /**
+ * Supported for Input and Output
+ */
AAUDIO_CHANNEL_2POINT0POINT2 = AAUDIO_CHANNEL_FRONT_LEFT |
AAUDIO_CHANNEL_FRONT_RIGHT |
AAUDIO_CHANNEL_TOP_SIDE_LEFT |
AAUDIO_CHANNEL_TOP_SIDE_RIGHT,
+ /**
+ * Supported for Input and Output
+ */
AAUDIO_CHANNEL_2POINT1POINT2 = AAUDIO_CHANNEL_2POINT0POINT2 |
AAUDIO_CHANNEL_LOW_FREQUENCY,
+ /**
+ * Supported for Input and Output
+ */
AAUDIO_CHANNEL_3POINT0POINT2 = AAUDIO_CHANNEL_FRONT_LEFT |
AAUDIO_CHANNEL_FRONT_RIGHT |
AAUDIO_CHANNEL_FRONT_CENTER |
AAUDIO_CHANNEL_TOP_SIDE_LEFT |
AAUDIO_CHANNEL_TOP_SIDE_RIGHT,
+ /**
+ * Supported for Input and Output
+ */
AAUDIO_CHANNEL_3POINT1POINT2 = AAUDIO_CHANNEL_3POINT0POINT2 |
AAUDIO_CHANNEL_LOW_FREQUENCY,
+ /**
+ * Supported for only Output
+ */
AAUDIO_CHANNEL_QUAD = AAUDIO_CHANNEL_FRONT_LEFT |
AAUDIO_CHANNEL_FRONT_RIGHT |
AAUDIO_CHANNEL_BACK_LEFT |
AAUDIO_CHANNEL_BACK_RIGHT,
+ /**
+ * Supported for only Output
+ */
AAUDIO_CHANNEL_QUAD_SIDE = AAUDIO_CHANNEL_FRONT_LEFT |
AAUDIO_CHANNEL_FRONT_RIGHT |
AAUDIO_CHANNEL_SIDE_LEFT |
AAUDIO_CHANNEL_SIDE_RIGHT,
+ /**
+ * Supported for only Output
+ */
AAUDIO_CHANNEL_SURROUND = AAUDIO_CHANNEL_FRONT_LEFT |
AAUDIO_CHANNEL_FRONT_RIGHT |
AAUDIO_CHANNEL_FRONT_CENTER |
AAUDIO_CHANNEL_BACK_CENTER,
+ /**
+ * Supported for only Output
+ */
AAUDIO_CHANNEL_PENTA = AAUDIO_CHANNEL_QUAD |
AAUDIO_CHANNEL_FRONT_CENTER,
- // aka 5POINT1_BACK
+ /**
+ * Supported for Input and Output. aka 5POINT1_BACK
+ */
AAUDIO_CHANNEL_5POINT1 = AAUDIO_CHANNEL_FRONT_LEFT |
AAUDIO_CHANNEL_FRONT_RIGHT |
AAUDIO_CHANNEL_FRONT_CENTER |
AAUDIO_CHANNEL_LOW_FREQUENCY |
AAUDIO_CHANNEL_BACK_LEFT |
AAUDIO_CHANNEL_BACK_RIGHT,
+ /**
+ * Supported for only Output
+ */
AAUDIO_CHANNEL_5POINT1_SIDE = AAUDIO_CHANNEL_FRONT_LEFT |
AAUDIO_CHANNEL_FRONT_RIGHT |
AAUDIO_CHANNEL_FRONT_CENTER |
AAUDIO_CHANNEL_LOW_FREQUENCY |
AAUDIO_CHANNEL_SIDE_LEFT |
AAUDIO_CHANNEL_SIDE_RIGHT,
+ /**
+ * Supported for only Output
+ */
AAUDIO_CHANNEL_6POINT1 = AAUDIO_CHANNEL_FRONT_LEFT |
AAUDIO_CHANNEL_FRONT_RIGHT |
AAUDIO_CHANNEL_FRONT_CENTER |
@@ -724,32 +775,55 @@
AAUDIO_CHANNEL_BACK_LEFT |
AAUDIO_CHANNEL_BACK_RIGHT |
AAUDIO_CHANNEL_BACK_CENTER,
+ /**
+ * Supported for only Output
+ */
AAUDIO_CHANNEL_7POINT1 = AAUDIO_CHANNEL_5POINT1 |
AAUDIO_CHANNEL_SIDE_LEFT |
AAUDIO_CHANNEL_SIDE_RIGHT,
+ /**
+ * Supported for only Output
+ */
AAUDIO_CHANNEL_5POINT1POINT2 = AAUDIO_CHANNEL_5POINT1 |
AAUDIO_CHANNEL_TOP_SIDE_LEFT |
AAUDIO_CHANNEL_TOP_SIDE_RIGHT,
+ /**
+ * Supported for only Output
+ */
AAUDIO_CHANNEL_5POINT1POINT4 = AAUDIO_CHANNEL_5POINT1 |
AAUDIO_CHANNEL_TOP_FRONT_LEFT |
AAUDIO_CHANNEL_TOP_FRONT_RIGHT |
AAUDIO_CHANNEL_TOP_BACK_LEFT |
AAUDIO_CHANNEL_TOP_BACK_RIGHT,
+ /**
+ * Supported for only Output
+ */
AAUDIO_CHANNEL_7POINT1POINT2 = AAUDIO_CHANNEL_7POINT1 |
AAUDIO_CHANNEL_TOP_SIDE_LEFT |
AAUDIO_CHANNEL_TOP_SIDE_RIGHT,
+ /**
+ * Supported for only Output
+ */
AAUDIO_CHANNEL_7POINT1POINT4 = AAUDIO_CHANNEL_7POINT1 |
AAUDIO_CHANNEL_TOP_FRONT_LEFT |
AAUDIO_CHANNEL_TOP_FRONT_RIGHT |
AAUDIO_CHANNEL_TOP_BACK_LEFT |
AAUDIO_CHANNEL_TOP_BACK_RIGHT,
+ /**
+ * Supported for only Output
+ */
AAUDIO_CHANNEL_9POINT1POINT4 = AAUDIO_CHANNEL_7POINT1POINT4 |
AAUDIO_CHANNEL_FRONT_WIDE_LEFT |
AAUDIO_CHANNEL_FRONT_WIDE_RIGHT,
+ /**
+ * Supported for only Output
+ */
AAUDIO_CHANNEL_9POINT1POINT6 = AAUDIO_CHANNEL_9POINT1POINT4 |
AAUDIO_CHANNEL_TOP_SIDE_LEFT |
AAUDIO_CHANNEL_TOP_SIDE_RIGHT,
-
+ /**
+ * Supported for only Input
+ */
AAUDIO_CHANNEL_FRONT_BACK = AAUDIO_CHANNEL_FRONT_CENTER |
AAUDIO_CHANNEL_BACK_CENTER,
};
diff --git a/media/libaaudio/src/client/AAudioFlowGraph.cpp b/media/libaaudio/src/client/AAudioFlowGraph.cpp
index 69be050..b7e0ae6 100644
--- a/media/libaaudio/src/client/AAudioFlowGraph.cpp
+++ b/media/libaaudio/src/client/AAudioFlowGraph.cpp
@@ -89,9 +89,9 @@
}
if (sourceSampleRate != sinkSampleRate) {
- mResampler.reset(aaudio::resampler::MultiChannelResampler::make(sinkChannelCount,
+ mResampler.reset(aaudio::resampler::MultiChannelResampler::make(sourceChannelCount,
sourceSampleRate, sinkSampleRate, resamplerQuality));
- mRateConverter = std::make_unique<SampleRateConverter>(sinkChannelCount,
+ mRateConverter = std::make_unique<SampleRateConverter>(sourceChannelCount,
*mResampler);
lastOutput->connect(&mRateConverter->input);
lastOutput = &mRateConverter->output;
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index d75832f..9b1ad72 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -134,8 +134,6 @@
request.getConfiguration().setBufferCapacity(builder.getBufferCapacity());
- mDeviceChannelCount = getSamplesPerFrame(); // Assume it will be the same. Update if not.
-
mServiceStreamHandleInfo = mServiceInterface.openStream(request, configurationOutput);
if (getServiceHandle() < 0
&& (request.getConfiguration().getSamplesPerFrame() == 1
@@ -179,8 +177,6 @@
setChannelMask(configurationOutput.getChannelMask());
}
- mDeviceChannelCount = configurationOutput.getSamplesPerFrame();
-
setDeviceId(configurationOutput.getDeviceId());
setSessionId(configurationOutput.getSessionId());
setSharingMode(configurationOutput.getSharingMode());
@@ -205,6 +201,7 @@
// Save device format so we can do format conversion and volume scaling together.
setDeviceFormat(configurationOutput.getFormat());
+ setDeviceSamplesPerFrame(configurationOutput.getSamplesPerFrame());
setHardwareSamplesPerFrame(configurationOutput.getHardwareSamplesPerFrame());
setHardwareSampleRate(configurationOutput.getHardwareSampleRate());
diff --git a/media/libaaudio/src/client/AudioStreamInternal.h b/media/libaaudio/src/client/AudioStreamInternal.h
index 0dc9995..a5981b1 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.h
+++ b/media/libaaudio/src/client/AudioStreamInternal.h
@@ -138,8 +138,6 @@
// Calculate timeout for an operation involving framesPerOperation.
int64_t calculateReasonableTimeout(int32_t framesPerOperation);
- int32_t getDeviceChannelCount() const { return mDeviceChannelCount; }
-
/**
* @return true if running in audio service, versus in app process
*/
@@ -213,10 +211,6 @@
int64_t mServiceLatencyNanos = 0;
- // Sometimes the hardware is operating with a different channel count from the app.
- // Then we require conversion in AAudio.
- int32_t mDeviceChannelCount = 0;
-
int32_t mBufferSizeInFrames = 0; // local threshold to control latency
int32_t mDeviceBufferSizeInFrames = 0;
int32_t mBufferCapacityInFrames = 0;
diff --git a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
index 47518d7..7d7b4ef 100644
--- a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
@@ -51,7 +51,7 @@
aaudio_result_t result = AudioStreamInternal::open(builder);
if (result == AAUDIO_OK) {
result = mFlowGraph.configure(getDeviceFormat(),
- getDeviceChannelCount(),
+ getDeviceSamplesPerFrame(),
getDeviceSampleRate(),
getFormat(),
getSamplesPerFrame(),
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
index 99aa910..ac927ae 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
@@ -54,7 +54,7 @@
getSamplesPerFrame(),
getSampleRate(),
getDeviceFormat(),
- getDeviceChannelCount(),
+ getDeviceSamplesPerFrame(),
getDeviceSampleRate(),
getRequireMonoBlend(),
useVolumeRamps,
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index 1649eaf..f2f5cac 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -252,6 +252,10 @@
return mSamplesPerFrame;
}
+ aaudio_result_t getDeviceSamplesPerFrame() const {
+ return mDeviceSamplesPerFrame;
+ }
+
aaudio_result_t getHardwareSamplesPerFrame() const {
return mHardwareSamplesPerFrame;
}
@@ -334,10 +338,10 @@
}
/**
- * This is only valid after setChannelMask() and setDeviceFormat() have been called.
+ * This is only valid after setDeviceSamplesPerFrame() and setDeviceFormat() have been called.
*/
int32_t getBytesPerDeviceFrame() const {
- return getSamplesPerFrame() * audio_bytes_per_sample(getDeviceFormat());
+ return getDeviceSamplesPerFrame() * audio_bytes_per_sample(getDeviceFormat());
}
virtual int64_t getFramesWritten() = 0;
@@ -377,6 +381,11 @@
mSamplesPerFrame = AAudioConvert_channelMaskToCount(channelMask);
}
+ void setDeviceSamplesPerFrame(int32_t deviceSamplesPerFrame) {
+ mDeviceSamplesPerFrame = deviceSamplesPerFrame;
+ }
+
+
/**
* @return true if data callback has been specified
*/
@@ -748,6 +757,7 @@
// These do not change after open().
int32_t mSamplesPerFrame = AAUDIO_UNSPECIFIED;
+ int32_t mDeviceSamplesPerFrame = AAUDIO_UNSPECIFIED;
int32_t mHardwareSamplesPerFrame = AAUDIO_UNSPECIFIED;
aaudio_channel_mask_t mChannelMask = AAUDIO_UNSPECIFIED;
int32_t mSampleRate = AAUDIO_UNSPECIFIED;
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index 7b4821f..fe4bf2c 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -208,6 +208,8 @@
setBufferCapacity(getBufferCapacityFromDevice());
setFramesPerBurst(getFramesPerBurstFromDevice());
+ // Use the same values for device values.
+ setDeviceSamplesPerFrame(getSamplesPerFrame());
setDeviceSampleRate(mAudioRecord->getSampleRate());
setDeviceBufferCapacity(getBufferCapacityFromDevice());
setDeviceFramesPerBurst(getFramesPerBurstFromDevice());
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index 723b419..59fdabc 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -202,6 +202,9 @@
setSampleRate(mAudioTrack->getSampleRate());
setBufferCapacity(getBufferCapacityFromDevice());
setFramesPerBurst(getFramesPerBurstFromDevice());
+
+ // Use the same values for device values.
+ setDeviceSamplesPerFrame(getSamplesPerFrame());
setDeviceSampleRate(mAudioTrack->getSampleRate());
setDeviceBufferCapacity(getBufferCapacityFromDevice());
setDeviceFramesPerBurst(getFramesPerBurstFromDevice());
diff --git a/media/libaudiohal/impl/EffectConversionHelperAidl.cpp b/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
index 8a582a5..9cf0cb8 100644
--- a/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
+++ b/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
@@ -208,12 +208,12 @@
mEffect->close();
return status;
}
- mCommon = common;
} else if (mCommon != common) {
ALOGI("%s at state %s, setParameter", __func__, android::internal::ToString(state).c_str());
- Parameter aidlParam = UNION_MAKE(Parameter, common, mCommon);
+ Parameter aidlParam = UNION_MAKE(Parameter, common, common);
RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->setParameter(aidlParam)));
}
+ mCommon = common;
return *static_cast<int32_t*>(pReplyData) = OK;
}
@@ -351,9 +351,14 @@
if (mIsProxyEffect) {
ALOGI("%s offload param offload %s ioHandle %d", __func__,
offload->isOffload ? "true" : "false", offload->ioHandle);
- mCommon.ioHandle = offload->ioHandle;
const auto& effectProxy = std::static_pointer_cast<EffectProxy>(mEffect);
RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(effectProxy->setOffloadParam(offload)));
+ if (mCommon.ioHandle != offload->ioHandle) {
+ ALOGI("%s ioHandle update [%d to %d]", __func__, mCommon.ioHandle, offload->ioHandle);
+ mCommon.ioHandle = offload->ioHandle;
+ Parameter aidlParam = UNION_MAKE(Parameter, common, mCommon);
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->setParameter(aidlParam)));
+ }
// update FMQs if the effect instance already open
if (State state; effectProxy->getState(&state).isOk() && state != State::INIT) {
mStatusQ = effectProxy->getStatusMQ();
diff --git a/media/libaudiohal/impl/EffectProxy.cpp b/media/libaudiohal/impl/EffectProxy.cpp
index a131879..5e465d9 100644
--- a/media/libaudiohal/impl/EffectProxy.cpp
+++ b/media/libaudiohal/impl/EffectProxy.cpp
@@ -15,6 +15,7 @@
*/
#include <algorithm>
+#include <cstddef>
#include <iterator>
#include <memory>
#define LOG_TAG "EffectProxy"
@@ -92,11 +93,13 @@
}
mActiveSubIdx = std::distance(mSubEffects.begin(), itor);
- ALOGV("%s: active %soffload sub-effect %zu descriptor: %s", __func__,
+ ALOGI("%s: active %soffload sub-effect %zu descriptor: %s", __func__,
offload->isOffload ? "" : "non-", mActiveSubIdx,
::android::audio::utils::toString(mSubEffects[mActiveSubIdx].descriptor.common.id.uuid)
.c_str());
- return ndk::ScopedAStatus::ok();
+ return runWithAllSubEffects([&](std::shared_ptr<IEffect>& effect) {
+ return effect->setParameter(Parameter::make<Parameter::offload>(offload->isOffload));
+ });
}
// EffectProxy go over sub-effects and call IEffect interfaces
diff --git a/media/libaudiohal/tests/EffectProxy_test.cpp b/media/libaudiohal/tests/EffectProxy_test.cpp
index 8668e85..2953b0a 100644
--- a/media/libaudiohal/tests/EffectProxy_test.cpp
+++ b/media/libaudiohal/tests/EffectProxy_test.cpp
@@ -53,7 +53,9 @@
void SetUp() override {
auto serviceName = android::getAidlHalInstanceNames(IFactory::descriptor);
// only unit test with the first one in case more than one EffectFactory service exist
- ASSERT_NE(0ul, serviceName.size());
+ if (0ul == serviceName.size()) {
+ GTEST_SKIP() << "EffectFactory not available on device, skipping";
+ }
mFactory = IFactory::fromBinder(
ndk::SpAIBinder(AServiceManager_waitForService(serviceName[0].c_str())));
ASSERT_NE(nullptr, mFactory);
@@ -157,6 +159,7 @@
effect_offload_param_t offloadParam{false, 0};
EXPECT_TRUE(proxy->setOffloadParam(&offloadParam).isOk());
offloadParam.isOffload = true;
+ offloadParam.ioHandle++;
EXPECT_TRUE(proxy->setOffloadParam(&offloadParam).isOk());
EXPECT_TRUE(proxy->close().isOk());
EXPECT_TRUE(proxy->destroy().isOk());
@@ -189,21 +192,21 @@
Parameter::Common common = createParamCommon();
IEffect::OpenEffectReturn ret;
Parameter::VolumeStereo volumeStereo({.left = .1f, .right = -0.8f});
- Parameter param = Parameter::make<Parameter::volumeStereo>(volumeStereo);
- Parameter::Id id = Parameter::Id::make<Parameter::Id::commonTag>(Parameter::volumeStereo);
+ Parameter expect = Parameter::make<Parameter::volumeStereo>(volumeStereo);
+ const Parameter::Id id = Parameter::Id::make<Parameter::Id::commonTag>(Parameter::volumeStereo);
State state;
for (const auto& itor : proxyMap) {
- Parameter expect;
+ Parameter getParam = Parameter::make<Parameter::offload>(true);
auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
effect_offload_param_t offloadParam{true, 0};
EXPECT_TRUE(proxy->setOffloadParam(&offloadParam).isOk());
EXPECT_TRUE(proxy->open(common, std::nullopt, &ret).isOk());
- EXPECT_TRUE(proxy->setParameter(param).isOk());
- EXPECT_TRUE(proxy->getParameter(id, &expect).isOk());
- EXPECT_EQ(expect, param) << " EXPECTED: " << expect.toString()
- << "\nACTUAL: " << param.toString();
+ EXPECT_TRUE(proxy->setParameter(expect).isOk());
+ EXPECT_TRUE(proxy->getParameter(id, &getParam).isOk());
+ EXPECT_EQ(expect, getParam)
+ << " EXPECTED: " << expect.toString() << "\nACTUAL: " << getParam.toString();
EXPECT_TRUE(proxy->command(CommandId::START).isOk());
EXPECT_TRUE(proxy->getState(&state).isOk());
@@ -225,25 +228,25 @@
Parameter::Common common = createParamCommon();
IEffect::OpenEffectReturn ret;
Parameter::VolumeStereo volumeStereo({.left = .5f, .right = .8f});
- Parameter param = Parameter::make<Parameter::volumeStereo>(volumeStereo);
- Parameter::Id id = Parameter::Id::make<Parameter::Id::commonTag>(Parameter::volumeStereo);
+ Parameter expect = Parameter::make<Parameter::volumeStereo>(volumeStereo);
+ const Parameter::Id id = Parameter::Id::make<Parameter::Id::commonTag>(Parameter::volumeStereo);
for (const auto& itor : proxyMap) {
- Parameter expect;
+ Parameter getParam = Parameter::make<Parameter::offload>(true);
auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
EXPECT_TRUE(proxy->open(common, std::nullopt, &ret).isOk());
- EXPECT_TRUE(proxy->setParameter(param).isOk());
- EXPECT_TRUE(proxy->getParameter(id, &expect).isOk());
- EXPECT_EQ(expect, param);
+ EXPECT_TRUE(proxy->setParameter(expect).isOk());
+ EXPECT_TRUE(proxy->getParameter(id, &getParam).isOk());
+ EXPECT_EQ(expect, getParam);
effect_offload_param_t offloadParam{false, 0};
EXPECT_TRUE(proxy->setOffloadParam(&offloadParam).isOk());
- EXPECT_TRUE(proxy->getParameter(id, &expect).isOk());
- EXPECT_EQ(expect, param);
+ EXPECT_TRUE(proxy->getParameter(id, &getParam).isOk());
+ EXPECT_EQ(expect, getParam);
offloadParam.isOffload = true;
EXPECT_TRUE(proxy->setOffloadParam(&offloadParam).isOk());
- EXPECT_TRUE(proxy->getParameter(id, &expect).isOk());
- EXPECT_EQ(expect, param);
+ EXPECT_TRUE(proxy->getParameter(id, &getParam).isOk());
+ EXPECT_EQ(expect, getParam);
EXPECT_TRUE(proxy->close().isOk());
EXPECT_TRUE(proxy->destroy().isOk());
@@ -271,13 +274,9 @@
effect_offload_param_t offloadParam{false, 0};
EXPECT_TRUE(proxy->setOffloadParam(&offloadParam).isOk());
- EXPECT_TRUE(proxy->getState(&state).isOk());
- EXPECT_EQ(State::PROCESSING, state);
offloadParam.isOffload = true;
EXPECT_TRUE(proxy->setOffloadParam(&offloadParam).isOk());
- EXPECT_TRUE(proxy->getState(&state).isOk());
- EXPECT_EQ(State::PROCESSING, state);
EXPECT_TRUE(proxy->command(CommandId::STOP).isOk());
EXPECT_TRUE(proxy->getState(&state).isOk());
diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp
index 1551e33..8d408dd 100644
--- a/media/libeffects/visualizer/EffectVisualizer.cpp
+++ b/media/libeffects/visualizer/EffectVisualizer.cpp
@@ -165,6 +165,7 @@
pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_ACCUMULATE) return -EINVAL;
if (pConfig->inputCfg.format != kProcessFormat) return -EINVAL;
+ pContext->mChannelCount = channelCount;
pContext->mConfig = *pConfig;
Visualizer_reset(pContext);
@@ -229,8 +230,6 @@
pContext->mScalingMode = VISUALIZER_SCALING_MODE_NORMALIZED;
// measurement initialization
- pContext->mChannelCount =
- audio_channel_count_from_out_mask(pContext->mConfig.inputCfg.channels);
pContext->mMeasurementMode = MEASUREMENT_MODE_NONE;
pContext->mMeasurementWindowSizeInBuffers = MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS;
pContext->mMeasurementBufferIdx = 0;
diff --git a/media/mtp/MtpFfsHandle.cpp b/media/mtp/MtpFfsHandle.cpp
index 2ffd775..ef8c9aa 100644
--- a/media/mtp/MtpFfsHandle.cpp
+++ b/media/mtp/MtpFfsHandle.cpp
@@ -297,6 +297,10 @@
}
void MtpFfsHandle::close() {
+ auto timeout = std::chrono::seconds(2);
+ std::unique_lock lk(m);
+ cv.wait_for(lk, timeout ,[this]{return child_threads==0;});
+
io_destroy(mCtx);
closeEndpoints();
closeConfig();
@@ -669,6 +673,11 @@
char *temp = new char[me.length];
memcpy(temp, me.data, me.length);
me.data = temp;
+
+ std::unique_lock lk(m);
+ child_threads++;
+ lk.unlock();
+
std::thread t([this, me]() { return this->doSendEvent(me); });
t.detach();
return 0;
@@ -680,6 +689,11 @@
if (static_cast<unsigned>(ret) != length)
PLOG(ERROR) << "Mtp error sending event thread!";
delete[] reinterpret_cast<char*>(me.data);
+
+ std::unique_lock lk(m);
+ child_threads--;
+ lk.unlock();
+ cv.notify_one();
}
} // namespace android
diff --git a/media/mtp/MtpFfsHandle.h b/media/mtp/MtpFfsHandle.h
index e552e03..51cdef0 100644
--- a/media/mtp/MtpFfsHandle.h
+++ b/media/mtp/MtpFfsHandle.h
@@ -60,6 +60,10 @@
bool mCanceled;
bool mBatchCancel;
+ std::mutex m;
+ std::condition_variable cv;
+ std::atomic<int> child_threads{0};
+
android::base::unique_fd mControl;
// "in" from the host's perspective => sink for mtp server
android::base::unique_fd mBulkIn;
diff --git a/services/audioflinger/Android.bp b/services/audioflinger/Android.bp
index 6329bae..7663250 100644
--- a/services/audioflinger/Android.bp
+++ b/services/audioflinger/Android.bp
@@ -196,6 +196,7 @@
srcs: [
"AudioFlinger.cpp",
+ "Client.cpp",
"DeviceEffectManager.cpp",
"Effects.cpp",
"MelReporter.cpp",
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index a9315f7..1e59bf8 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -15,7 +15,6 @@
** limitations under the License.
*/
-
#define LOG_TAG "AudioFlinger"
//#define LOG_NDEBUG 0
@@ -23,71 +22,44 @@
#define AUDIO_ARRAYS_STATIC_CHECK 1
#include "Configuration.h"
-#include <dirent.h>
-#include <math.h>
-#include <signal.h>
-#include <string>
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <thread>
-
-#include <android-base/stringprintf.h>
-#include <android/media/IAudioPolicyService.h>
-#include <android/os/IExternalVibratorService.h>
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <utils/Log.h>
-#include <utils/Trace.h>
-#include <binder/Parcel.h>
-#include <media/audiohal/AudioHalVersionInfo.h>
-#include <media/audiohal/DeviceHalInterface.h>
-#include <media/audiohal/DevicesFactoryHalInterface.h>
-#include <media/audiohal/EffectsFactoryHalInterface.h>
-#include <media/AudioParameter.h>
-#include <media/MediaMetricsItem.h>
-#include <media/TypeConverter.h>
-#include <mediautils/TimeCheck.h>
-#include <memunreachable/memunreachable.h>
-#include <utils/String16.h>
-#include <utils/threads.h>
-
-#include <cutils/atomic.h>
-#include <cutils/properties.h>
-
-#include <system/audio.h>
-#include <audiomanager/IAudioManager.h>
-
#include "AudioFlinger.h"
#include "EffectConfiguration.h"
+
+//#define BUFLOG_NDEBUG 0
+#include <afutils/BufLog.h>
+#include <afutils/DumpTryLock.h>
+#include <afutils/Permission.h>
#include <afutils/PropertyUtils.h>
-
-#include <media/AudioResamplerPublic.h>
-
-#include <system/audio_effects/effect_visualizer.h>
-#include <system/audio_effects/effect_ns.h>
-#include <system/audio_effects/effect_aec.h>
-#include <system/audio_effects/effect_hapticgenerator.h>
-#include <system/audio_effects/effect_spatializer.h>
-
-#include <audio_utils/primitives.h>
-
-#include <powermanager/PowerManager.h>
-
-#include <media/IMediaLogService.h>
+#include <afutils/TypedLogger.h>
+#include <android-base/stringprintf.h>
+#include <android/media/IAudioPolicyService.h>
+#include <audiomanager/IAudioManager.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <cutils/properties.h>
#include <media/AidlConversion.h>
+#include <media/AudioParameter.h>
#include <media/AudioValidator.h>
-#include <media/nbaio/Pipe.h>
-#include <media/nbaio/PipeReader.h>
+#include <media/IMediaLogService.h>
+#include <media/MediaMetricsItem.h>
+#include <media/TypeConverter.h>
#include <mediautils/BatteryNotifier.h>
#include <mediautils/MemoryLeakTrackUtil.h>
#include <mediautils/MethodStatistics.h>
#include <mediautils/ServiceUtilities.h>
#include <mediautils/TimeCheck.h>
-#include <private/android_filesystem_config.h>
+#include <memunreachable/memunreachable.h>
+// required for effect matching
+#include <system/audio_effects/effect_aec.h>
+#include <system/audio_effects/effect_ns.h>
+#include <system/audio_effects/effect_spatializer.h>
+#include <system/audio_effects/effect_visualizer.h>
+#include <utils/Log.h>
-//#define BUFLOG_NDEBUG 0
-#include <afutils/BufLog.h>
-#include <afutils/TypedLogger.h>
+// not needed with the includes above, added to prevent transitive include dependency.
+#include <chrono>
+#include <thread>
// ----------------------------------------------------------------------------
@@ -124,10 +96,6 @@
static constexpr char kAudioServiceName[] = "audio";
-nsecs_t AudioFlinger::mStandbyTimeInNsecs = kDefaultStandbyTimeInNsecs;
-
-uint32_t AudioFlinger::mScreenState;
-
// In order to avoid invalidating offloaded tracks each time a Visualizer is turned on and off
// we define a minimum time during which a global effect is considered enabled.
static const nsecs_t kMinGlobalEffectEnabletimeNs = seconds(7200);
@@ -148,21 +116,6 @@
}
}
-// Keep a strong reference to external vibrator service
-static sp<os::IExternalVibratorService> sExternalVibratorService;
-
-static sp<os::IExternalVibratorService> getExternalVibratorService() {
- if (sExternalVibratorService == 0) {
- sp<IBinder> binder = defaultServiceManager()->getService(
- String16("external_vibrator_service"));
- if (binder != 0) {
- sExternalVibratorService =
- interface_cast<os::IExternalVibratorService>(binder);
- }
- }
- return sExternalVibratorService;
-}
-
// Creates association between Binder code to name for IAudioFlinger.
#define IAUDIOFLINGER_BINDER_METHOD_MACRO_LIST \
BINDER_METHOD_ENTRY(createTrack) \
@@ -269,41 +222,6 @@
}
};
-// TODO b/182392769: use attribution source util
-/* static */
-AttributionSourceState AudioFlinger::checkAttributionSourcePackage(
- const AttributionSourceState& attributionSource) {
- Vector<String16> packages;
- PermissionController{}.getPackagesForUid(attributionSource.uid, packages);
-
- AttributionSourceState checkedAttributionSource = attributionSource;
- if (!attributionSource.packageName.has_value()
- || attributionSource.packageName.value().size() == 0) {
- if (!packages.isEmpty()) {
- checkedAttributionSource.packageName =
- std::move(legacy2aidl_String16_string(packages[0]).value());
- }
- } else {
- String16 opPackageLegacy = VALUE_OR_FATAL(
- aidl2legacy_string_view_String16(attributionSource.packageName.value_or("")));
- if (std::find_if(packages.begin(), packages.end(),
- [&opPackageLegacy](const auto& package) {
- return opPackageLegacy == package; }) == packages.end()) {
- ALOGW("The package name(%s) provided does not correspond to the uid %d",
- attributionSource.packageName.value_or("").c_str(), attributionSource.uid);
- }
- }
- return checkedAttributionSource;
-}
-
-// ----------------------------------------------------------------------------
-
-std::string formatToString(audio_format_t format) {
- std::string result;
- FormatConverter::toString(format, result);
- return result;
-}
-
// ----------------------------------------------------------------------------
void AudioFlinger::instantiate() {
@@ -385,20 +303,6 @@
{
Mutex::Autolock _l(mLock);
- /* TODO: move all this work into an Init() function */
- char val_str[PROPERTY_VALUE_MAX] = { 0 };
- if (property_get("ro.audio.flinger_standbytime_ms", val_str, NULL) >= 0) {
- uint32_t int_val;
- if (1 == sscanf(val_str, "%u", &int_val)) {
- mStandbyTimeInNsecs = milliseconds(int_val);
- ALOGI("Using %u mSec as standby time.", int_val);
- } else {
- mStandbyTimeInNsecs = kDefaultStandbyTimeInNsecs;
- ALOGI("Using default %u mSec as standby time.",
- (uint32_t)(mStandbyTimeInNsecs / 1000000));
- }
- }
-
mMode = AUDIO_MODE_NORMAL;
gAudioFlinger = this; // we are already refcounted, store into atomic pointer.
@@ -581,7 +485,7 @@
sp<MmapStreamInterface>& interface,
audio_port_handle_t *handle)
{
- // TODO: Use ServiceManager to get IAudioFlinger instead of by atomic pointer.
+ // TODO(b/292281786): Use ServiceManager to get IAudioFlinger instead of by atomic pointer.
// This allows moving oboeservice (AAudio) to a separate process in the future.
sp<AudioFlinger> af = AudioFlinger::gAudioFlinger.load(); // either nullptr or singleton AF.
status_t ret = NO_INIT;
@@ -639,7 +543,7 @@
__func__, callingUid, callingPid, clientPid);
adjAttributionSource.pid = VALUE_OR_RETURN_STATUS(legacy2aidl_pid_t_int32_t(callingPid));
}
- adjAttributionSource = AudioFlinger::checkAttributionSourcePackage(
+ adjAttributionSource = afutils::checkAttributionSourcePackage(
adjAttributionSource);
if (direction == MmapStreamInterface::DIRECTION_OUTPUT) {
@@ -702,34 +606,6 @@
return ret;
}
-/* static */
-os::HapticScale AudioFlinger::onExternalVibrationStart(
- const sp<os::ExternalVibration>& externalVibration) {
- sp<os::IExternalVibratorService> evs = getExternalVibratorService();
- if (evs != nullptr) {
- int32_t ret;
- binder::Status status = evs->onExternalVibrationStart(*externalVibration, &ret);
- if (status.isOk()) {
- ALOGD("%s, start external vibration with intensity as %d", __func__, ret);
- return os::ExternalVibration::externalVibrationScaleToHapticScale(ret);
- }
- }
- ALOGD("%s, start external vibration with intensity as MUTE due to %s",
- __func__,
- evs == nullptr ? "external vibration service not found"
- : "error when querying intensity");
- return os::HapticScale::MUTE;
-}
-
-/* static */
-void AudioFlinger::onExternalVibrationStop(const sp<os::ExternalVibration>& externalVibration) {
- sp<os::IExternalVibratorService> evs = getExternalVibratorService();
- if (evs != 0) {
- ALOGD("%s, stopping external vibration", __func__);
- evs->onExternalVibrationStop(*externalVibration);
- }
-}
-
status_t AudioFlinger::addEffectToHal(
const struct audio_port_config *device, const sp<EffectHalInterface>& effect) {
AutoMutex lock(mHardwareLock);
@@ -830,10 +706,7 @@
String8 result;
hardware_call_state hardwareStatus = mHardwareStatus;
- snprintf(buffer, SIZE, "Hardware status: %d\n"
- "Standby Time mSec: %u\n",
- hardwareStatus,
- (uint32_t)(mStandbyTimeInNsecs / 1000000));
+ snprintf(buffer, SIZE, "Hardware status: %d\n", hardwareStatus);
result.append(buffer);
write(fd, result.string(), result.size());
@@ -858,12 +731,6 @@
write(fd, result.string(), result.size());
}
-bool AudioFlinger::dumpTryLock(Mutex& mutex)
-{
- status_t err = mutex.timedLock(kDumpLockTimeoutNs);
- return err == NO_ERROR;
-}
-
status_t AudioFlinger::dump(int fd, const Vector<String16>& args)
NO_THREAD_SAFETY_ANALYSIS // conditional try lock
{
@@ -871,7 +738,7 @@
dumpPermissionDenial(fd, args);
} else {
// get state of hardware lock
- bool hardwareLocked = dumpTryLock(mHardwareLock);
+ const bool hardwareLocked = afutils::dumpTryLock(mHardwareLock);
if (!hardwareLocked) {
String8 result(kHardwareLockedString);
write(fd, result.string(), result.size());
@@ -879,7 +746,7 @@
mHardwareLock.unlock();
}
- const bool locked = dumpTryLock(mLock);
+ const bool locked = afutils::dumpTryLock(mLock);
// failed to lock - AudioFlinger is probably deadlocked
if (!locked) {
@@ -887,7 +754,7 @@
write(fd, result.string(), result.size());
}
- bool clientLocked = dumpTryLock(mClientLock);
+ const bool clientLocked = afutils::dumpTryLock(mClientLock);
if (!clientLocked) {
String8 result(kClientLockedString);
write(fd, result.string(), result.size());
@@ -1145,7 +1012,7 @@
clientPid = callingPid;
adjAttributionSource.pid = VALUE_OR_RETURN_STATUS(legacy2aidl_pid_t_int32_t(callingPid));
}
- adjAttributionSource = AudioFlinger::checkAttributionSourcePackage(
+ adjAttributionSource = afutils::checkAttributionSourcePackage(
adjAttributionSource);
audio_session_t sessionId = input.sessionId;
@@ -1955,8 +1822,8 @@
String8 screenState;
if (param.get(String8(AudioParameter::keyScreenState), screenState) == NO_ERROR) {
bool isOff = (screenState == AudioParameter::valueOff);
- if (isOff != (AudioFlinger::mScreenState & 1)) {
- AudioFlinger::mScreenState = ((AudioFlinger::mScreenState & ~1) + 2) | isOff;
+ if (isOff != (mScreenState & 1)) {
+ mScreenState = ((mScreenState & ~1) + 2) | isOff;
}
}
return final_result;
@@ -2311,27 +2178,6 @@
return thread;
}
-
-
-// ----------------------------------------------------------------------------
-
-Client::Client(const sp<IAfClientCallback>& afClientCallback, pid_t pid)
- : RefBase(),
- mAfClientCallback(afClientCallback),
- mPid(pid),
- mClientAllocator(AllocatorFactory::getClientAllocator()) {}
-
-// Client destructor must be called with AudioFlinger::mClientLock held
-Client::~Client()
-{
- mAfClientCallback->removeClient_l(mPid);
-}
-
-AllocatorFactory::ClientAllocator& Client::allocator()
-{
- return mClientAllocator;
-}
-
// ----------------------------------------------------------------------------
AudioFlinger::NotificationClient::NotificationClient(const sp<AudioFlinger>& audioFlinger,
@@ -2428,7 +2274,7 @@
__func__, callingUid, callingPid, currentPid);
adjAttributionSource.pid = VALUE_OR_RETURN_STATUS(legacy2aidl_pid_t_int32_t(callingPid));
}
- adjAttributionSource = AudioFlinger::checkAttributionSourcePackage(
+ adjAttributionSource = afutils::checkAttributionSourcePackage(
adjAttributionSource);
// we don't yet support anything other than linear PCM
if (!audio_is_valid_format(input.config.format) || !audio_is_linear_pcm(input.config.format)) {
@@ -3005,28 +2851,6 @@
}
mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
-
- // FOR TESTING ONLY:
- // This if statement allows overriding the audio policy settings
- // and forcing a specific format or channel mask to the HAL/Sink device for testing.
- if (!(flags & (AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD | AUDIO_OUTPUT_FLAG_DIRECT))) {
- // Check only for Normal Mixing mode
- if (kEnableExtendedPrecision) {
- // Specify format (uncomment one below to choose)
- //halConfig->format = AUDIO_FORMAT_PCM_FLOAT;
- //halConfig->format = AUDIO_FORMAT_PCM_24_BIT_PACKED;
- //halConfig->format = AUDIO_FORMAT_PCM_32_BIT;
- //halConfig->format = AUDIO_FORMAT_PCM_8_24_BIT;
- // ALOGV("openOutput_l() upgrading format to %#08x", halConfig->format);
- }
- if (kEnableExtendedChannels) {
- // Specify channel mask (uncomment one below to choose)
- //halConfig->channel_mask = audio_channel_out_mask_from_count(4); // for USB 4ch
- //halConfig->channel_mask = audio_channel_mask_from_representation_and_bits(
- // AUDIO_CHANNEL_REPRESENTATION_INDEX, (1 << 4) - 1); // another 4ch example
- }
- }
-
AudioStreamOut *outputStream = NULL;
status_t status = outHwDev->openOutputStream(
&outputStream,
@@ -3064,8 +2888,8 @@
ALOGV("openOutput_l() created offload output: ID %d thread %p",
*output, thread.get());
} else if ((flags & AUDIO_OUTPUT_FLAG_DIRECT)
- || !isValidPcmSinkFormat(halConfig->format)
- || !isValidPcmSinkChannelMask(halConfig->channel_mask)) {
+ || !IAfThreadBase::isValidPcmSinkFormat(halConfig->format)
+ || !IAfThreadBase::isValidPcmSinkChannelMask(halConfig->channel_mask)) {
thread = IAfPlaybackThread::createDirectOutputThread(this, outputStream, *output,
mSystemReady, halConfig->offload_info);
ALOGV("openOutput_l() created direct output: ID %d thread %p",
@@ -4208,7 +4032,7 @@
adjAttributionSource.pid = VALUE_OR_RETURN_STATUS(legacy2aidl_pid_t_int32_t(callingPid));
currentPid = callingPid;
}
- adjAttributionSource = AudioFlinger::checkAttributionSourcePackage(adjAttributionSource);
+ adjAttributionSource = afutils::checkAttributionSourcePackage(adjAttributionSource);
ALOGV("createEffect pid %d, effectClient %p, priority %d, sessionId %d, io %d, factory %p",
adjAttributionSource.pid, effectClient.get(), priority, sessionId, io,
@@ -4847,6 +4671,55 @@
return false;
}
+// ----------------------------------------------------------------------------
+// from PatchPanel
+
+/* List connected audio ports and their attributes */
+status_t AudioFlinger::listAudioPorts(unsigned int* num_ports,
+ struct audio_port* ports) const
+{
+ Mutex::Autolock _l(mLock);
+ return mPatchPanel->listAudioPorts(num_ports, ports);
+}
+
+/* Get supported attributes for a given audio port */
+status_t AudioFlinger::getAudioPort(struct audio_port_v7* port) const {
+ const status_t status = AudioValidator::validateAudioPort(*port);
+ if (status != NO_ERROR) {
+ return status;
+ }
+
+ Mutex::Autolock _l(mLock);
+ return mPatchPanel->getAudioPort(port);
+}
+
+/* Connect a patch between several source and sink ports */
+status_t AudioFlinger::createAudioPatch(
+ const struct audio_patch* patch, audio_patch_handle_t* handle)
+{
+ const status_t status = AudioValidator::validateAudioPatch(*patch);
+ if (status != NO_ERROR) {
+ return status;
+ }
+
+ Mutex::Autolock _l(mLock);
+ return mPatchPanel->createAudioPatch(patch, handle);
+}
+
+/* Disconnect a patch */
+status_t AudioFlinger::releaseAudioPatch(audio_patch_handle_t handle)
+{
+ Mutex::Autolock _l(mLock);
+ return mPatchPanel->releaseAudioPatch(handle);
+}
+
+/* List connected audio ports and they attributes */
+status_t AudioFlinger::listAudioPatches(
+ unsigned int* num_patches, struct audio_patch* patches) const
+{
+ Mutex::Autolock _l(mLock);
+ return mPatchPanel->listAudioPatches(num_patches, patches);
+}
// ----------------------------------------------------------------------------
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 737dffe..9aefb6b 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -15,150 +15,38 @@
** limitations under the License.
*/
-#ifndef ANDROID_AUDIO_FLINGER_H
-#define ANDROID_AUDIO_FLINGER_H
+#pragma once
-#include "Configuration.h"
-#include <atomic>
-#include <mutex>
-#include <chrono>
-#include <deque>
-#include <map>
-#include <numeric>
-#include <optional>
-#include <set>
-#include <string>
-#include <vector>
-#include <stdint.h>
-#include <sys/types.h>
-#include <limits.h>
-
-#include <android/media/BnAudioTrack.h>
-#include <android/media/IAudioFlingerClient.h>
-#include <android/media/IAudioTrackCallback.h>
-#include <android/os/BnExternalVibrationController.h>
-#include <android/content/AttributionSourceState.h>
-
-
-#include <android-base/macros.h>
-#include <cutils/atomic.h>
-#include <cutils/compiler.h>
-
-#include <cutils/properties.h>
-#include <media/IAudioFlinger.h>
-#include <media/AudioSystem.h>
-#include <media/AudioTrack.h>
-#include <media/MmapStreamInterface.h>
-#include <media/MmapStreamCallback.h>
-
-#include <utils/Errors.h>
-#include <utils/threads.h>
-#include <utils/SortedVector.h>
-#include <utils/TypeHelpers.h>
-#include <utils/Vector.h>
-
-#include <binder/AppOpsManager.h>
-#include <binder/BinderService.h>
-#include <binder/IAppOpsCallback.h>
-#include <binder/MemoryDealer.h>
-
-#include <system/audio.h>
-#include <system/audio_policy.h>
-
-#include <media/audiohal/EffectBufferHalInterface.h>
-#include <media/audiohal/StreamHalInterface.h>
-#include <media/AudioBufferProvider.h>
-#include <media/AudioContainers.h>
-#include <media/AudioDeviceTypeAddr.h>
-#include <media/AudioMixer.h>
-#include <media/DeviceDescriptorBase.h>
-#include <media/ExtendedAudioBufferProvider.h>
-#include <media/VolumeShaper.h>
-#include <mediautils/BatteryNotifier.h>
-#include <mediautils/ServiceUtilities.h>
-#include <mediautils/SharedMemoryAllocator.h>
-#include <mediautils/Synchronization.h>
-#include <mediautils/ThreadSnapshot.h>
-
-#include <afutils/AllocatorFactory.h>
-#include <afutils/AudioWatchdog.h>
-#include <afutils/NBAIO_Tee.h>
-
-#include <audio_utils/clock.h>
-#include <audio_utils/FdToString.h>
-#include <audio_utils/LinearMap.h>
-#include <audio_utils/MelAggregator.h>
-#include <audio_utils/MelProcessor.h>
-#include <audio_utils/SimpleLog.h>
-#include <audio_utils/TimestampVerifier.h>
-
-#include <sounddose/SoundDoseManager.h>
-#include <timing/MonotonicFrameCounter.h>
-#include <timing/SyncEvent.h>
-#include <timing/SynchronizedRecordState.h>
-
-#include <datapath/AudioHwDevice.h>
-#include <datapath/AudioStreamIn.h>
-#include <datapath/AudioStreamOut.h>
-#include <datapath/SpdifStreamOut.h>
-#include <datapath/ThreadMetrics.h>
-#include <datapath/TrackMetrics.h>
-#include <datapath/VolumeInterface.h>
-#include <fastpath/FastCapture.h>
-#include <fastpath/FastMixer.h>
-#include <media/nbaio/NBAIO.h>
-
-#include <android/os/IPowerManager.h>
-
-#include <media/nblog/NBLog.h>
-#include <private/media/AudioEffectShared.h>
-#include <private/media/AudioTrackShared.h>
-
-#include <vibrator/ExternalVibration.h>
-#include <vibrator/ExternalVibrationUtils.h>
-
-#include "android/media/BnAudioRecord.h"
-#include "android/media/BnEffect.h"
-
+// Classes and interfaces directly used.
#include "Client.h"
-#include "ResamplerBufferProvider.h"
-
-// include AudioFlinger component interfaces
-#include "IAfPatchPanel.h" // this should be listed before other IAf* interfaces.
+#include "DeviceEffectManager.h"
#include "IAfEffect.h"
+#include "IAfPatchPanel.h"
#include "IAfThread.h"
#include "IAfTrack.h"
-
-// Classes that depend on IAf* interfaces but are not cross-dependent.
-#include "PatchCommandThread.h"
-#include "DeviceEffectManager.h"
#include "MelReporter.h"
+#include "PatchCommandThread.h"
+
+// External classes
+#include <audio_utils/FdToString.h>
+#include <audio_utils/SimpleLog.h>
+#include <media/IAudioFlinger.h>
+#include <media/MediaMetricsItem.h>
+#include <media/audiohal/DevicesFactoryHalInterface.h>
+#include <mediautils/ServiceUtilities.h>
+#include <mediautils/Synchronization.h>
+
+// not needed with the includes above, added to prevent transitive include dependency.
+#include <utils/KeyedVector.h>
+#include <utils/String16.h>
+#include <atomic>
+#include <functional>
+#include <map>
+#include <optional>
+#include <set>
namespace android {
-class AudioMixer;
-class AudioBuffer;
-class AudioResampler;
-class DeviceHalInterface;
-class DevicesFactoryHalCallback;
-class DevicesFactoryHalInterface;
-class EffectsFactoryHalInterface;
-class FastMixer;
-class IAudioManager;
-class PassthruBufferProvider;
-class ServerProxy;
-
-// ----------------------------------------------------------------------------
-
-static const nsecs_t kDefaultStandbyTimeInNsecs = seconds(3);
-
-using android::content::AttributionSourceState;
-
-struct stream_type_t {
- float volume = 1.f;
- bool mute = false;
-};
-
class AudioFlinger
: public AudioFlingerServerAdapter::Delegate // IAudioFlinger client interface
, public IAfClientCallback
@@ -171,9 +59,6 @@
public:
static void instantiate() ANDROID_API;
- static AttributionSourceState checkAttributionSourcePackage(
- const AttributionSourceState& attributionSource);
-
private:
// ---- begin IAudioFlinger interface
@@ -429,6 +314,7 @@
bool streamMute_l(audio_stream_type_t stream) const final { return mStreamTypes[stream].mute; }
audio_mode_t getMode() const final { return mMode; }
bool isLowRamDevice() const final { return mIsLowRamDevice; }
+ uint32_t getScreenState() const final { return mScreenState; }
std::optional<media::AudioVibratorInfo> getDefaultVibratorInfo_l() const final;
const sp<IAfPatchPanel>& getPatchPanel() const final { return mPatchPanel; }
@@ -474,6 +360,10 @@
sp<EffectsFactoryHalInterface> getEffectsFactory();
public:
+ // TODO(b/292281786): Remove this when Oboeservice can get access to
+ // openMmapStream through an IAudioFlinger handle directly.
+ static inline std::atomic<AudioFlinger*> gAudioFlinger = nullptr;
+
status_t openMmapStream(MmapStreamInterface::stream_direction_t direction,
const audio_attributes_t *attr,
audio_config_base_t *config,
@@ -483,11 +373,6 @@
const sp<MmapStreamCallback>& callback,
sp<MmapStreamInterface>& interface,
audio_port_handle_t *handle);
-
- static os::HapticScale onExternalVibrationStart(
- const sp<os::ExternalVibration>& externalVibration);
- static void onExternalVibrationStop(const sp<os::ExternalVibration>& externalVibration);
-
private:
// FIXME The 400 is temporarily too high until a leak of writers in media.log is fixed.
static const size_t kLogMemorySize = 400 * 1024;
@@ -510,77 +395,10 @@
AudioHwDevice* findSuitableHwDev_l(audio_module_handle_t module,
audio_devices_t deviceType);
- // Set kEnableExtendedChannels to true to enable greater than stereo output
- // for the MixerThread and device sink. Number of channels allowed is
- // FCC_2 <= channels <= AudioMixer::MAX_NUM_CHANNELS.
- static const bool kEnableExtendedChannels = true;
-
-public:
- // Remove this when Oboeservice is updated to obtain handle directly.
- static inline std::atomic<AudioFlinger*> gAudioFlinger = nullptr;
-
- // Returns true if channel mask is permitted for the PCM sink in the MixerThread
- static inline bool isValidPcmSinkChannelMask(audio_channel_mask_t channelMask) {
- switch (audio_channel_mask_get_representation(channelMask)) {
- case AUDIO_CHANNEL_REPRESENTATION_POSITION: {
- // Haptic channel mask is only applicable for channel position mask.
- const uint32_t channelCount = audio_channel_count_from_out_mask(
- static_cast<audio_channel_mask_t>(channelMask & ~AUDIO_CHANNEL_HAPTIC_ALL));
- const uint32_t maxChannelCount = kEnableExtendedChannels
- ? AudioMixer::MAX_NUM_CHANNELS : FCC_2;
- if (channelCount < FCC_2 // mono is not supported at this time
- || channelCount > maxChannelCount) {
- return false;
- }
- // check that channelMask is the "canonical" one we expect for the channelCount.
- return audio_channel_position_mask_is_out_canonical(channelMask);
- }
- case AUDIO_CHANNEL_REPRESENTATION_INDEX:
- if (kEnableExtendedChannels) {
- const uint32_t channelCount = audio_channel_count_from_out_mask(channelMask);
- if (channelCount >= FCC_2 // mono is not supported at this time
- && channelCount <= AudioMixer::MAX_NUM_CHANNELS) {
- return true;
- }
- }
- return false;
- default:
- return false;
- }
- }
-
- // Set kEnableExtendedPrecision to true to use extended precision in MixerThread
- static const bool kEnableExtendedPrecision = true;
-
- // Returns true if format is permitted for the PCM sink in the MixerThread
- static inline bool isValidPcmSinkFormat(audio_format_t format) {
- switch (format) {
- case AUDIO_FORMAT_PCM_16_BIT:
- return true;
- case AUDIO_FORMAT_PCM_FLOAT:
- case AUDIO_FORMAT_PCM_24_BIT_PACKED:
- case AUDIO_FORMAT_PCM_32_BIT:
- case AUDIO_FORMAT_PCM_8_24_BIT:
- return kEnableExtendedPrecision;
- default:
- return false;
- }
- }
-
- // standby delay for MIXER and DUPLICATING playback threads is read from property
- // ro.audio.flinger_standbytime_ms or defaults to kDefaultStandbyTimeInNsecs
- static nsecs_t mStandbyTimeInNsecs;
-
// incremented by 2 when screen state changes, bit 0 == 1 means "off"
- // AudioFlinger::setParameters() updates, other threads read w/o lock
- static uint32_t mScreenState;
+ // AudioFlinger::setParameters() updates with mLock.
+ std::atomic_uint32_t mScreenState{};
- // Internal dump utilities.
- static const int kDumpLockTimeoutNs = 1 * NANOS_PER_SECOND;
-
- // TODO(b/291319167) extract to afutils
- static bool dumpTryLock(Mutex& mutex);
-private:
void dumpPermissionDenial(int fd, const Vector<String16>& args);
void dumpClients(int fd, const Vector<String16>& args);
void dumpInternals(int fd, const Vector<String16>& args);
@@ -878,11 +696,6 @@
static inline constexpr const char *mMetricsId = AMEDIAMETRICS_KEY_AUDIO_FLINGER;
-public:
- // Keep in sync with java definition in media/java/android/media/AudioRecord.java
- static constexpr int32_t kMaxSharedAudioHistoryMs = 5000;
-private:
-
std::map<media::audio::common::AudioMMapPolicyType,
std::vector<media::audio::common::AudioMMapPolicyInfo>> mPolicyInfos;
int32_t mAAudioBurstsPerBuffer = 0;
@@ -895,14 +708,6 @@
std::atomic_bool mBluetoothLatencyModesEnabled;
};
-std::string formatToString(audio_format_t format);
-std::string inputFlagsToString(audio_input_flags_t flags);
-std::string outputFlagsToString(audio_output_flags_t flags);
-std::string devicesToString(audio_devices_t devices);
-const char *sourceToString(audio_source_t source);
-
// ----------------------------------------------------------------------------
} // namespace android
-
-#endif // ANDROID_AUDIO_FLINGER_H
diff --git a/services/audioflinger/Client.cpp b/services/audioflinger/Client.cpp
new file mode 100644
index 0000000..93599ac
--- /dev/null
+++ b/services/audioflinger/Client.cpp
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+#include "Client.h"
+
+namespace android {
+
+Client::Client(const sp<IAfClientCallback>& afClientCallback, pid_t pid)
+ : mAfClientCallback(afClientCallback)
+ , mPid(pid)
+ , mClientAllocator(AllocatorFactory::getClientAllocator()) {}
+
+// Client destructor must be called with AudioFlinger::mClientLock held
+Client::~Client()
+{
+ mAfClientCallback->removeClient_l(mPid);
+}
+
+AllocatorFactory::ClientAllocator& Client::allocator()
+{
+ return mClientAllocator;
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/services/audioflinger/Client.h b/services/audioflinger/Client.h
index 36d6ff7..b2e3cf7 100644
--- a/services/audioflinger/Client.h
+++ b/services/audioflinger/Client.h
@@ -16,6 +16,11 @@
#pragma once
+#include <afutils/AllocatorFactory.h>
+#include <android-base/macros.h> // DISALLOW_COPY_AND_ASSIGN
+#include <utils/Mutex.h>
+#include <utils/RefBase.h> // avoid transitive dependency
+
// TODO(b/291318727) Move to nested namespace
namespace android {
@@ -29,7 +34,7 @@
virtual status_t moveAuxEffectToIo(
int effectId,
const sp<IAfPlaybackThread>& dstThread,
- sp<IAfPlaybackThread>* srcThread) = 0;
+ sp<IAfPlaybackThread>* srcThread) = 0; // used by indirectly by clients.
};
class Client : public RefBase {
diff --git a/services/audioflinger/DeviceEffectManager.cpp b/services/audioflinger/DeviceEffectManager.cpp
index d78e26f..681ec5f 100644
--- a/services/audioflinger/DeviceEffectManager.cpp
+++ b/services/audioflinger/DeviceEffectManager.cpp
@@ -15,16 +15,17 @@
** limitations under the License.
*/
-
#define LOG_TAG "DeviceEffectManager"
//#define LOG_NDEBUG 0
-#include <utils/Log.h>
-#include <audio_utils/primitives.h>
+#include "DeviceEffectManager.h"
-#include "AudioFlinger.h"
#include "EffectConfiguration.h"
+
+#include <afutils/DumpTryLock.h>
+#include <audio_utils/primitives.h>
#include <media/audiohal/EffectsFactoryHalInterface.h>
+#include <utils/Log.h>
// ----------------------------------------------------------------------------
@@ -202,7 +203,7 @@
void DeviceEffectManager::dump(int fd)
NO_THREAD_SAFETY_ANALYSIS // conditional try lock
{
- const bool locked = AudioFlinger::dumpTryLock(mLock);
+ const bool locked = afutils::dumpTryLock(mLock);
if (!locked) {
String8 result("DeviceEffectManager may be deadlocked\n");
write(fd, result.string(), result.size());
diff --git a/services/audioflinger/DeviceEffectManager.h b/services/audioflinger/DeviceEffectManager.h
index 3da5504..cb7fad1 100644
--- a/services/audioflinger/DeviceEffectManager.h
+++ b/services/audioflinger/DeviceEffectManager.h
@@ -17,6 +17,11 @@
#pragma once
+#include "IAfEffect.h"
+#include "PatchCommandThread.h"
+
+#include <utils/Mutex.h> // avoid transitive dependency
+
namespace android {
class IAfDeviceEffectManagerCallback : public virtual RefBase {
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index ce71703..c3e1fba 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -19,10 +19,25 @@
#define LOG_TAG "AudioFlinger"
//#define LOG_NDEBUG 0
-#include <algorithm>
+#include "Effects.h"
-#include "Configuration.h"
-#include <utils/Log.h>
+#include "Client.h"
+#include "EffectConfiguration.h"
+
+#include <afutils/DumpTryLock.h>
+#include <audio_utils/channels.h>
+#include <audio_utils/primitives.h>
+#include <media/AudioCommonTypes.h>
+#include <media/AudioContainers.h>
+#include <media/AudioDeviceTypeAddr.h>
+#include <media/AudioEffect.h>
+#include <media/ShmemCompat.h>
+#include <media/TypeConverter.h>
+#include <media/audiohal/EffectHalInterface.h>
+#include <media/audiohal/EffectsFactoryHalInterface.h>
+#include <mediautils/MethodStatistics.h>
+#include <mediautils/ServiceUtilities.h>
+#include <mediautils/TimeCheck.h>
#include <system/audio_effects/effect_aec.h>
#include <system/audio_effects/effect_downmix.h>
#include <system/audio_effects/effect_dynamicsprocessing.h>
@@ -30,22 +45,9 @@
#include <system/audio_effects/effect_ns.h>
#include <system/audio_effects/effect_spatializer.h>
#include <system/audio_effects/effect_visualizer.h>
-#include <audio_utils/channels.h>
-#include <audio_utils/primitives.h>
-#include <media/AudioCommonTypes.h>
-#include <media/AudioContainers.h>
-#include <media/AudioEffect.h>
-#include <media/AudioDeviceTypeAddr.h>
-#include <media/ShmemCompat.h>
-#include <media/audiohal/EffectHalInterface.h>
-#include <media/audiohal/EffectsFactoryHalInterface.h>
-#include <mediautils/MethodStatistics.h>
-#include <mediautils/ServiceUtilities.h>
-#include <mediautils/TimeCheck.h>
+#include <utils/Log.h>
-#include "AudioFlinger.h"
-#include "EffectConfiguration.h"
-#include "Effects.h"
+#include <algorithm>
// ----------------------------------------------------------------------------
@@ -507,7 +509,7 @@
result.appendFormat("\tEffect ID %d:\n", mId);
- bool locked = AudioFlinger::dumpTryLock(mLock);
+ const bool locked = afutils::dumpTryLock(mLock);
// failed to lock - AudioFlinger is probably deadlocked
if (!locked) {
result.append("\t\tCould not lock Fx mutex:\n");
@@ -1623,7 +1625,7 @@
EffectBase::dump(fd, args);
String8 result;
- bool locked = AudioFlinger::dumpTryLock(mLock);
+ const bool locked = afutils::dumpTryLock(mLock);
result.append("\t\tStatus Engine:\n");
result.appendFormat("\t\t%03d %p\n",
@@ -1639,7 +1641,7 @@
mConfig.inputCfg.samplingRate,
mConfig.inputCfg.channels,
mConfig.inputCfg.format,
- formatToString((audio_format_t)mConfig.inputCfg.format).c_str());
+ toString(static_cast<audio_format_t>(mConfig.inputCfg.format)).c_str());
result.append("\t\t- Output configuration:\n");
result.append("\t\t\tBuffer Frames Smp rate Channels Format\n");
@@ -1649,7 +1651,7 @@
mConfig.outputCfg.samplingRate,
mConfig.outputCfg.channels,
mConfig.outputCfg.format,
- formatToString((audio_format_t)mConfig.outputCfg.format).c_str());
+ toString(static_cast<audio_format_t>(mConfig.outputCfg.format)).c_str());
result.appendFormat("\t\t- HAL buffers:\n"
"\t\t\tIn(%s) InConversion(%s) Out(%s) OutConversion(%s)\n",
@@ -2097,7 +2099,7 @@
void EffectHandle::dumpToBuffer(char* buffer, size_t size) const
NO_THREAD_SAFETY_ANALYSIS // conditional try lock
{
- bool locked = mCblk != NULL && AudioFlinger::dumpTryLock(mCblk->lock);
+ const bool locked = mCblk != nullptr && afutils::dumpTryLock(mCblk->lock);
snprintf(buffer, size, "\t\t\t%5d %5d %3s %3s %5u %5u\n",
(mClient == 0) ? getpid() : mClient->pid(),
@@ -2646,7 +2648,7 @@
result.appendFormat(" %zu effects for session %d\n", numEffects, mSessionId);
if (numEffects) {
- bool locked = AudioFlinger::dumpTryLock(mLock);
+ const bool locked = afutils::dumpTryLock(mLock);
// failed to lock - AudioFlinger is probably deadlocked
if (!locked) {
result.append("\tCould not lock mutex:\n");
@@ -3522,7 +3524,7 @@
const Vector<String16> args;
EffectBase::dump(fd, args);
- const bool locked = AudioFlinger::dumpTryLock(mProxyLock);
+ const bool locked = afutils::dumpTryLock(mProxyLock);
if (!locked) {
String8 result("DeviceEffectProxy may be deadlocked\n");
write(fd, result.string(), result.size());
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index dfa199e..79b4e63 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -15,6 +15,17 @@
** limitations under the License.
*/
+#pragma once
+
+#include "DeviceEffectManager.h"
+#include "IAfEffect.h"
+
+#include <android-base/macros.h> // DISALLOW_COPY_AND_ASSIGN
+#include <mediautils/Synchronization.h>
+#include <private/media/AudioEffectShared.h>
+
+#include <map> // avoid transitive dependency
+
namespace android {
//--- Audio Effect Management
diff --git a/services/audioflinger/IAfEffect.h b/services/audioflinger/IAfEffect.h
index 9e3f7fd..c4f0de3 100644
--- a/services/audioflinger/IAfEffect.h
+++ b/services/audioflinger/IAfEffect.h
@@ -16,9 +16,22 @@
#pragma once
+#include "IAfPatchPanel.h" // full class Patch definition needed
+
+#include <android/media/AudioVibratorInfo.h>
+#include <android/media/BnEffect.h>
+#include <android/media/BnEffectClient.h>
+#include <media/AudioCommonTypes.h> // product_strategy_t
+#include <media/AudioDeviceTypeAddr.h>
+#include <media/audiohal/EffectHalInterface.h>
+#include <utils/RefBase.h>
+#include <vibrator/ExternalVibration.h>
+
namespace android {
+class Client;
class DeviceEffectManagerCallback;
+
class IAfDeviceEffectProxy;
class IAfEffectBase;
class IAfEffectChain;
diff --git a/services/audioflinger/IAfPatchPanel.h b/services/audioflinger/IAfPatchPanel.h
index bc116a9..20e092d 100644
--- a/services/audioflinger/IAfPatchPanel.h
+++ b/services/audioflinger/IAfPatchPanel.h
@@ -16,15 +16,20 @@
#pragma once
+// The following includes are required because we have class definitions below
+// for EndPoint and Patch, which precludes using a forward declaration only.
+#include "IAfThread.h" // IAfThreadBase IAfMmapThread IAfPlaybackThread IAfRecordThread
+#include "IAfTrack.h" // IAfPatchRecord IAfPatchTrack
+
+#include <datapath/AudioHwDevice.h>
+#include <media/DeviceDescriptorBase.h>
+#include <utils/Log.h> // ALOG used in this file
+#include <utils/RefBase.h> // avoid transitive dependency
+#include <utils/Thread.h>
+
namespace android {
-class IAfMmapThread;
class IAfPatchPanel;
-class IAfPatchRecord;
-class IAfPatchTrack;
-class IAfPlaybackThread;
-class IAfRecordThread;
-class IAfThreadBase;
class PatchCommandThread;
class SoftwarePatch {
diff --git a/services/audioflinger/IAfThread.h b/services/audioflinger/IAfThread.h
index deb019f..be51d51 100644
--- a/services/audioflinger/IAfThread.h
+++ b/services/audioflinger/IAfThread.h
@@ -16,7 +16,25 @@
#pragma once
-#include "IAfTrack.h"
+#include <android/media/IAudioTrackCallback.h>
+#include <android/media/IEffectClient.h>
+#include <audiomanager/IAudioManager.h>
+#include <audio_utils/MelProcessor.h>
+#include <binder/MemoryDealer.h>
+#include <datapath/AudioStreamIn.h>
+#include <datapath/AudioStreamOut.h>
+#include <datapath/VolumeInterface.h>
+#include <fastpath/FastMixerDumpState.h>
+#include <media/DeviceDescriptorBase.h>
+#include <media/MmapStreamInterface.h>
+#include <media/audiohal/StreamHalInterface.h>
+#include <media/nblog/NBLog.h>
+#include <timing/SyncEvent.h>
+#include <utils/Mutex.h>
+#include <utils/RefBase.h>
+#include <vibrator/ExternalVibration.h>
+
+#include <optional>
namespace android {
@@ -26,8 +44,25 @@
class IAfMmapPlaybackThread;
class IAfPlaybackThread;
class IAfRecordThread;
+
+class IAfEffectChain;
+class IAfEffectHandle;
+class IAfEffectModule;
+class IAfPatchPanel;
+class IAfPatchRecord;
+class IAfPatchTrack;
+class IAfRecordTrack;
+class IAfTrack;
+class IAfTrackBase;
+class Client;
class MelReporter;
+// Used internally for Threads.cpp and AudioFlinger.cpp
+struct stream_type_t {
+ float volume = 1.f;
+ bool mute = false;
+};
+
// Note this is exposed through IAfThreadBase::afThreadCallback()
// and hence may be used by the Effect / Track framework.
class IAfThreadCallback : public virtual RefBase {
@@ -43,6 +78,7 @@
virtual audio_mode_t getMode() const = 0;
virtual bool isLowRamDevice() const = 0;
virtual bool isAudioPolicyReady() const = 0; // Effects
+ virtual uint32_t getScreenState() const = 0;
virtual std::optional<media::AudioVibratorInfo> getDefaultVibratorInfo_l() const = 0;
virtual const sp<IAfPatchPanel>& getPatchPanel() const = 0;
virtual const sp<MelReporter>& getMelReporter() const = 0;
@@ -87,6 +123,10 @@
};
static const char* threadTypeToString(type_t type);
+ static std::string formatToString(audio_format_t format); // compliant for MediaMetrics
+ static bool isValidPcmSinkChannelMask(audio_channel_mask_t channelMask);
+ static bool isValidPcmSinkFormat(audio_format_t format);
+
virtual status_t readyToRun() = 0;
virtual void clearPowerManager() = 0;
virtual status_t initCheck() const = 0;
diff --git a/services/audioflinger/IAfTrack.h b/services/audioflinger/IAfTrack.h
index 2763157..2302e13 100644
--- a/services/audioflinger/IAfTrack.h
+++ b/services/audioflinger/IAfTrack.h
@@ -16,8 +16,27 @@
#pragma once
+#include <android/media/BnAudioRecord.h>
+#include <android/media/BnAudioTrack.h>
+#include <audiomanager/IAudioManager.h>
+#include <binder/IMemory.h>
+#include <fastpath/FastMixerDumpState.h>
+#include <media/AudioSystem.h>
+#include <media/VolumeShaper.h>
+#include <private/media/AudioTrackShared.h>
+#include <timing/SyncEvent.h>
+#include <timing/SynchronizedRecordState.h>
+#include <utils/RefBase.h>
+#include <vibrator/ExternalVibration.h>
+
+#include <vector>
+
namespace android {
+class Client;
+class ResamplerBufferProvider;
+struct Source;
+
class IAfDuplicatingThread;
class IAfPatchRecord;
class IAfPatchTrack;
diff --git a/services/audioflinger/MelReporter.cpp b/services/audioflinger/MelReporter.cpp
index 35400e1..f3256a7 100644
--- a/services/audioflinger/MelReporter.cpp
+++ b/services/audioflinger/MelReporter.cpp
@@ -18,7 +18,7 @@
// #define LOG_NDEBUG 0
#define LOG_TAG "MelReporter"
-#include "AudioFlinger.h"
+#include "MelReporter.h"
#include <android/media/ISoundDoseCallback.h>
#include <audio_utils/power.h>
diff --git a/services/audioflinger/MelReporter.h b/services/audioflinger/MelReporter.h
index 0dbb5f8..005ca96 100644
--- a/services/audioflinger/MelReporter.h
+++ b/services/audioflinger/MelReporter.h
@@ -17,8 +17,12 @@
#pragma once
-#include <mutex>
+#include "IAfPatchPanel.h"
+#include "PatchCommandThread.h"
+
#include <sounddose/SoundDoseManager.h>
+
+#include <mutex>
#include <unordered_map>
namespace android {
diff --git a/services/audioflinger/MmapTracks.h b/services/audioflinger/MmapTracks.h
index c695098..85ce142 100644
--- a/services/audioflinger/MmapTracks.h
+++ b/services/audioflinger/MmapTracks.h
@@ -17,6 +17,10 @@
#pragma once
+#include "TrackBase.h"
+
+#include <android/content/AttributionSourceState.h>
+
namespace android {
// playback track
diff --git a/services/audioflinger/PatchCommandThread.cpp b/services/audioflinger/PatchCommandThread.cpp
index 2849da4..8d5eb9f 100644
--- a/services/audioflinger/PatchCommandThread.cpp
+++ b/services/audioflinger/PatchCommandThread.cpp
@@ -18,7 +18,9 @@
#define LOG_TAG "AudioFlinger::PatchCommandThread"
//#define LOG_NDEBUG 0
-#include "AudioFlinger.h"
+#include "PatchCommandThread.h"
+
+#include <utils/Log.h>
namespace android {
diff --git a/services/audioflinger/PatchCommandThread.h b/services/audioflinger/PatchCommandThread.h
index 6cf0505..66018d7 100644
--- a/services/audioflinger/PatchCommandThread.h
+++ b/services/audioflinger/PatchCommandThread.h
@@ -17,6 +17,14 @@
#pragma once
+#include "IAfPatchPanel.h"
+
+#include <utils/RefBase.h> // avoid transitive dependency
+#include <utils/Thread.h> // avoid transitive dependency
+
+#include <deque>
+#include <mutex> // avoid transitive dependency
+
namespace android {
class Command;
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index 3251345..f11a530 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -19,17 +19,16 @@
#define LOG_TAG "AudioFlinger::PatchPanel"
//#define LOG_NDEBUG 0
-#include "Configuration.h"
-#include <utils/Log.h>
-#include <audio_utils/primitives.h>
-
-#include "AudioFlinger.h"
#include "PatchPanel.h"
+#include "PatchCommandThread.h"
+
+#include <audio_utils/primitives.h>
#include <media/AudioParameter.h>
#include <media/AudioValidator.h>
#include <media/DeviceDescriptorBase.h>
#include <media/PatchBuilder.h>
#include <mediautils/ServiceUtilities.h>
+#include <utils/Log.h>
// ----------------------------------------------------------------------------
@@ -48,53 +47,6 @@
namespace android {
-/* List connected audio ports and their attributes */
-status_t AudioFlinger::listAudioPorts(unsigned int *num_ports,
- struct audio_port* ports) const
-{
- Mutex::Autolock _l(mLock);
- return mPatchPanel->listAudioPorts(num_ports, ports);
-}
-
-/* Get supported attributes for a given audio port */
-status_t AudioFlinger::getAudioPort(struct audio_port_v7* port) const {
- status_t status = AudioValidator::validateAudioPort(*port);
- if (status != NO_ERROR) {
- return status;
- }
-
- Mutex::Autolock _l(mLock);
- return mPatchPanel->getAudioPort(port);
-}
-
-/* Connect a patch between several source and sink ports */
-status_t AudioFlinger::createAudioPatch(const struct audio_patch *patch,
- audio_patch_handle_t *handle)
-{
- status_t status = AudioValidator::validateAudioPatch(*patch);
- if (status != NO_ERROR) {
- return status;
- }
-
- Mutex::Autolock _l(mLock);
- return mPatchPanel->createAudioPatch(patch, handle);
-}
-
-/* Disconnect a patch */
-status_t AudioFlinger::releaseAudioPatch(audio_patch_handle_t handle)
-{
- Mutex::Autolock _l(mLock);
- return mPatchPanel->releaseAudioPatch(handle);
-}
-
-/* List connected audio ports and they attributes */
-status_t AudioFlinger::listAudioPatches(
- unsigned int* num_patches, struct audio_patch* patches) const
-{
- Mutex::Autolock _l(mLock);
- return mPatchPanel->listAudioPatches(num_patches, patches);
-}
-
/* static */
sp<IAfPatchPanel> IAfPatchPanel::create(const sp<IAfPatchPanelCallback>& afPatchPanelCallback) {
return sp<PatchPanel>::make(afPatchPanelCallback);
diff --git a/services/audioflinger/PatchPanel.h b/services/audioflinger/PatchPanel.h
index a80a0e0..a95c601 100644
--- a/services/audioflinger/PatchPanel.h
+++ b/services/audioflinger/PatchPanel.h
@@ -17,6 +17,11 @@
#pragma once
+#include "IAfPatchPanel.h"
+
+#include <map> // avoid transitive dependency
+#include <set> // avoid transitive dependency
+
namespace android {
class PatchPanel : public IAfPatchPanel {
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 1d50621..978c4aa 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -16,8 +16,12 @@
*/
#pragma once
-#include <math.h>
-#include <sys/types.h>
+
+#include "TrackBase.h"
+
+#include <android/os/BnExternalVibrationController.h>
+#include <audio_utils/LinearMap.h>
+#include <binder/AppOpsManager.h>
namespace android {
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index 89e2f66..021add4 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -17,7 +17,10 @@
#pragma once
+#include "TrackBase.h"
+
#include <android/content/AttributionSourceState.h>
+#include <datapath/AudioStreamIn.h> // struct Source
namespace android {
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 1e1d925..575bcf9 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -20,45 +20,49 @@
// #define LOG_NDEBUG 0
#define ATRACE_TAG ATRACE_TAG_AUDIO
-#include "Configuration.h"
-#include <math.h>
-#include <fcntl.h>
-#include <memory>
-#include <sstream>
-#include <string>
-#include <linux/futex.h>
-#include <sys/stat.h>
-#include <sys/syscall.h>
+#include "Threads.h"
+
+#include "Client.h"
+#include "IAfEffect.h"
+#include "MelReporter.h"
+#include "ResamplerBufferProvider.h"
+
+#include <afutils/DumpTryLock.h>
+#include <afutils/Permission.h>
+#include <afutils/TypedLogger.h>
+#include <afutils/Vibrator.h>
+#include <audio_utils/MelProcessor.h>
+#include <audio_utils/Metadata.h>
+#ifdef DEBUG_CPU_USAGE
+#include <audio_utils/Statistics.h>
+#include <cpustats/ThreadCpuUsage.h>
+#endif
+#include <audio_utils/channels.h>
+#include <audio_utils/format.h>
+#include <audio_utils/minifloat.h>
+#include <audio_utils/mono_blend.h>
+#include <audio_utils/primitives.h>
+#include <audio_utils/safe_math.h>
+#include <audiomanager/AudioManager.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/PersistableBundle.h>
#include <cutils/bitops.h>
#include <cutils/properties.h>
-#include <binder/PersistableBundle.h>
+#include <fastpath/AutoPark.h>
#include <media/AudioContainers.h>
#include <media/AudioDeviceTypeAddr.h>
#include <media/AudioParameter.h>
#include <media/AudioResamplerPublic.h>
+#ifdef ADD_BATTERY_DATA
+#include <media/IMediaPlayerService.h>
+#include <media/IMediaDeathNotifier.h>
+#endif
+#include <media/MmapStreamCallback.h>
#include <media/RecordBufferConverter.h>
#include <media/TypeConverter.h>
-#include <utils/Log.h>
-#include <utils/Trace.h>
-
-#include <private/media/AudioTrackShared.h>
-#include <private/android_filesystem_config.h>
-#include <audio_utils/Balance.h>
-#include <audio_utils/MelProcessor.h>
-#include <audio_utils/Metadata.h>
-#include <audio_utils/channels.h>
-#include <audio_utils/mono_blend.h>
-#include <audio_utils/primitives.h>
-#include <audio_utils/format.h>
-#include <audio_utils/minifloat.h>
-#include <audio_utils/safe_math.h>
-#include <system/audio_effects/effect_aec.h>
-#include <system/audio_effects/effect_downmix.h>
-#include <system/audio_effects/effect_ns.h>
-#include <system/audio_effects/effect_spatializer.h>
-#include <system/audio.h>
-
-// NBAIO implementations
+#include <media/audiohal/EffectsFactoryHalInterface.h>
+#include <media/audiohal/StreamHalInterface.h>
#include <media/nbaio/AudioStreamInSource.h>
#include <media/nbaio/AudioStreamOutSink.h>
#include <media/nbaio/MonoPipe.h>
@@ -68,33 +72,27 @@
#include <media/nbaio/SourceAudioBufferProvider.h>
#include <mediautils/BatteryNotifier.h>
#include <mediautils/Process.h>
-
-#include <audiomanager/AudioManager.h>
-#include <powermanager/PowerManager.h>
-
-#include <media/audiohal/EffectsFactoryHalInterface.h>
-#include <media/audiohal/StreamHalInterface.h>
-
-#include "AudioFlinger.h"
-#include "Threads.h"
-
#include <mediautils/SchedulingPolicyService.h>
#include <mediautils/ServiceUtilities.h>
+#include <powermanager/PowerManager.h>
+#include <private/android_filesystem_config.h>
+#include <private/media/AudioTrackShared.h>
+#include <system/audio_effects/effect_aec.h>
+#include <system/audio_effects/effect_downmix.h>
+#include <system/audio_effects/effect_ns.h>
+#include <system/audio_effects/effect_spatializer.h>
+#include <utils/Log.h>
+#include <utils/Trace.h>
-#ifdef ADD_BATTERY_DATA
-#include <media/IMediaPlayerService.h>
-#include <media/IMediaDeathNotifier.h>
-#endif
-
-#ifdef DEBUG_CPU_USAGE
-#include <audio_utils/Statistics.h>
-#include <cpustats/ThreadCpuUsage.h>
-#endif
-
-#include <fastpath/AutoPark.h>
-
+#include <fcntl.h>
+#include <linux/futex.h>
+#include <math.h>
+#include <memory>
#include <pthread.h>
-#include <afutils/TypedLogger.h>
+#include <sstream>
+#include <string>
+#include <sys/stat.h>
+#include <sys/syscall.h>
// ----------------------------------------------------------------------------
@@ -126,6 +124,9 @@
using media::IEffectClient;
using content::AttributionSourceState;
+// Keep in sync with java definition in media/java/android/media/AudioRecord.java
+static constexpr int32_t kMaxSharedAudioHistoryMs = 5000;
+
// retry counts for buffer fill timeout
// 50 * ~20msecs = 1 second
static const int8_t kMaxTrackRetries = 50;
@@ -242,8 +243,84 @@
// and that all "fast" AudioRecord clients read from. In either case, the size can be small.
static const size_t kRecordThreadReadOnlyHeapSize = 0xD000;
+static const nsecs_t kDefaultStandbyTimeInNsecs = seconds(3);
+
+static nsecs_t getStandbyTimeInNanos() {
+ static nsecs_t standbyTimeInNanos = []() {
+ const int ms = property_get_int32("ro.audio.flinger_standbytime_ms",
+ kDefaultStandbyTimeInNsecs / NANOS_PER_MILLISECOND);
+ ALOGI("%s: Using %d ms as standby time", __func__, ms);
+ return milliseconds(ms);
+ }();
+ return standbyTimeInNanos;
+}
+
+// Set kEnableExtendedChannels to true to enable greater than stereo output
+// for the MixerThread and device sink. Number of channels allowed is
+// FCC_2 <= channels <= FCC_LIMIT.
+constexpr bool kEnableExtendedChannels = true;
+
+// Returns true if channel mask is permitted for the PCM sink in the MixerThread
+/* static */
+bool IAfThreadBase::isValidPcmSinkChannelMask(audio_channel_mask_t channelMask) {
+ switch (audio_channel_mask_get_representation(channelMask)) {
+ case AUDIO_CHANNEL_REPRESENTATION_POSITION: {
+ // Haptic channel mask is only applicable for channel position mask.
+ const uint32_t channelCount = audio_channel_count_from_out_mask(
+ static_cast<audio_channel_mask_t>(channelMask & ~AUDIO_CHANNEL_HAPTIC_ALL));
+ const uint32_t maxChannelCount = kEnableExtendedChannels
+ ? FCC_LIMIT : FCC_2;
+ if (channelCount < FCC_2 // mono is not supported at this time
+ || channelCount > maxChannelCount) {
+ return false;
+ }
+ // check that channelMask is the "canonical" one we expect for the channelCount.
+ return audio_channel_position_mask_is_out_canonical(channelMask);
+ }
+ case AUDIO_CHANNEL_REPRESENTATION_INDEX:
+ if (kEnableExtendedChannels) {
+ const uint32_t channelCount = audio_channel_count_from_out_mask(channelMask);
+ if (channelCount >= FCC_2 // mono is not supported at this time
+ && channelCount <= FCC_LIMIT) {
+ return true;
+ }
+ }
+ return false;
+ default:
+ return false;
+ }
+}
+
+// Set kEnableExtendedPrecision to true to use extended precision in MixerThread
+constexpr bool kEnableExtendedPrecision = true;
+
+// Returns true if format is permitted for the PCM sink in the MixerThread
+/* static */
+bool IAfThreadBase::isValidPcmSinkFormat(audio_format_t format) {
+ switch (format) {
+ case AUDIO_FORMAT_PCM_16_BIT:
+ return true;
+ case AUDIO_FORMAT_PCM_FLOAT:
+ case AUDIO_FORMAT_PCM_24_BIT_PACKED:
+ case AUDIO_FORMAT_PCM_32_BIT:
+ case AUDIO_FORMAT_PCM_8_24_BIT:
+ return kEnableExtendedPrecision;
+ default:
+ return false;
+ }
+}
+
// ----------------------------------------------------------------------------
+// formatToString() needs to be exact for MediaMetrics purposes.
+// Do not use media/TypeConverter.h toString().
+/* static */
+std::string IAfThreadBase::formatToString(audio_format_t format) {
+ std::string result;
+ FormatConverter::toString(format, result);
+ return result;
+}
+
// TODO: move all toString helpers to audio.h
// under #ifdef __cplusplus #endif
static std::string patchSinksToString(const struct audio_patch *patch)
@@ -949,7 +1026,7 @@
dprintf(fd, "\n%s thread %p, name %s, tid %d, type %d (%s):\n", isOutput() ? "Output" : "Input",
this, mThreadName, getTid(), type(), threadTypeToString(type()));
- bool locked = AudioFlinger::dumpTryLock(mLock);
+ const bool locked = afutils::dumpTryLock(mLock);
if (!locked) {
dprintf(fd, " Thread may be deadlocked\n");
}
@@ -987,12 +1064,14 @@
dprintf(fd, " Standby: %s\n", mStandby ? "yes" : "no");
dprintf(fd, " Sample rate: %u Hz\n", mSampleRate);
dprintf(fd, " HAL frame count: %zu\n", mFrameCount);
- dprintf(fd, " HAL format: 0x%x (%s)\n", mHALFormat, formatToString(mHALFormat).c_str());
+ dprintf(fd, " HAL format: 0x%x (%s)\n", mHALFormat,
+ IAfThreadBase::formatToString(mHALFormat).c_str());
dprintf(fd, " HAL buffer size: %zu bytes\n", mBufferSize);
dprintf(fd, " Channel count: %u\n", mChannelCount);
dprintf(fd, " Channel mask: 0x%08x (%s)\n", mChannelMask,
channelMaskToString(mChannelMask, mType != RECORD).string());
- dprintf(fd, " Processing format: 0x%x (%s)\n", mFormat, formatToString(mFormat).c_str());
+ dprintf(fd, " Processing format: 0x%x (%s)\n", mFormat,
+ IAfThreadBase::formatToString(mFormat).c_str());
dprintf(fd, " Processing frame size: %zu bytes\n", mFrameSize);
dprintf(fd, " Pending config events:");
size_t numConfig = mConfigEvents.size();
@@ -2040,12 +2119,12 @@
audio_config_base_t *mixerConfig)
: ThreadBase(afThreadCallback, id, type, systemReady, true /* isOut */),
mNormalFrameCount(0), mSinkBuffer(NULL),
- mMixerBufferEnabled(AudioFlinger::kEnableExtendedPrecision || type == SPATIALIZER),
+ mMixerBufferEnabled(kEnableExtendedPrecision || type == SPATIALIZER),
mMixerBuffer(NULL),
mMixerBufferSize(0),
mMixerBufferFormat(AUDIO_FORMAT_INVALID),
mMixerBufferValid(false),
- mEffectBufferEnabled(AudioFlinger::kEnableExtendedPrecision || type == SPATIALIZER),
+ mEffectBufferEnabled(kEnableExtendedPrecision || type == SPATIALIZER),
mEffectBuffer(NULL),
mEffectBufferSize(0),
mEffectBufferFormat(AUDIO_FORMAT_INVALID),
@@ -2060,13 +2139,13 @@
mNumWrites(0), mNumDelayedWrites(0), mInWrite(false),
mMixerStatus(MIXER_IDLE),
mMixerStatusIgnoringFastTracks(MIXER_IDLE),
- mStandbyDelayNs(AudioFlinger::mStandbyTimeInNsecs),
+ mStandbyDelayNs(getStandbyTimeInNanos()),
mBytesRemaining(0),
mCurrentWriteLength(0),
mUseAsyncWrite(false),
mWriteAckSequence(0),
mDrainSequence(0),
- mScreenState(AudioFlinger::mScreenState),
+ mScreenState(mAfThreadCallback->getScreenState()),
// index 0 is reserved for normal mixer's submix
mFastTrackAvailMask(((1 << FastMixerState::sMaxFastTracks) - 1) & ~1),
mHwSupportsPause(false), mHwPaused(false), mFlushPending(false),
@@ -2814,7 +2893,7 @@
// Unlock due to VibratorService will lock for this call and will
// call Tracks.mute/unmute which also require thread's lock.
mLock.unlock();
- const os::HapticScale intensity = AudioFlinger::onExternalVibrationStart(
+ const os::HapticScale intensity = afutils::onExternalVibrationStart(
track->getExternalVibration());
std::optional<media::AudioVibratorInfo> vibratorInfo;
{
@@ -3028,7 +3107,7 @@
if (!audio_is_output_channel(mChannelMask)) {
LOG_ALWAYS_FATAL("HAL channel mask %#x not valid for output", mChannelMask);
}
- if (hasMixer() && !AudioFlinger::isValidPcmSinkChannelMask(mChannelMask)) {
+ if (hasMixer() && !isValidPcmSinkChannelMask(mChannelMask)) {
LOG_ALWAYS_FATAL("HAL channel mask %#x not supported for mixed output",
mChannelMask);
}
@@ -3051,7 +3130,7 @@
if (!audio_is_valid_format(mFormat)) {
LOG_ALWAYS_FATAL("HAL format %#x not valid for output", mFormat);
}
- if (hasMixer() && !AudioFlinger::isValidPcmSinkFormat(mFormat)) {
+ if (hasMixer() && !isValidPcmSinkFormat(mFormat)) {
LOG_FATAL("HAL format %#x not supported for mixed output",
mFormat);
}
@@ -3197,7 +3276,7 @@
audio_output_flags_t flags = mOutput->flags;
mediametrics::LogItem item(mThreadMetrics.getMetricsId()); // TODO: method in ThreadMetrics?
item.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_READPARAMETERS)
- .set(AMEDIAMETRICS_PROP_ENCODING, formatToString(mFormat).c_str())
+ .set(AMEDIAMETRICS_PROP_ENCODING, IAfThreadBase::formatToString(mFormat).c_str())
.set(AMEDIAMETRICS_PROP_SAMPLERATE, (int32_t)mSampleRate)
.set(AMEDIAMETRICS_PROP_CHANNELMASK, (int32_t)mChannelMask)
.set(AMEDIAMETRICS_PROP_CHANNELCOUNT, (int32_t)mChannelCount)
@@ -3208,7 +3287,7 @@
.set(AMEDIAMETRICS_PROP_PREFIX_HAPTIC AMEDIAMETRICS_PROP_CHANNELCOUNT,
(int32_t)mHapticChannelCount)
.set(AMEDIAMETRICS_PROP_PREFIX_HAL AMEDIAMETRICS_PROP_ENCODING,
- formatToString(mHALFormat).c_str())
+ IAfThreadBase::formatToString(mHALFormat).c_str())
.set(AMEDIAMETRICS_PROP_PREFIX_HAL AMEDIAMETRICS_PROP_FRAMECOUNT,
(int32_t)mFrameCount) // sic - added HAL
;
@@ -3399,7 +3478,7 @@
ATRACE_BEGIN("write");
// update the setpoint when AudioFlinger::mScreenState changes
- uint32_t screenState = AudioFlinger::mScreenState;
+ const uint32_t screenState = mAfThreadCallback->getScreenState();
if (screenState != mScreenState) {
mScreenState = screenState;
MonoPipe *pipe = (MonoPipe *)mPipeSink.get();
@@ -3533,7 +3612,7 @@
mActiveSleepTimeUs = activeSleepTimeUs();
mIdleSleepTimeUs = idleSleepTimeUs();
- mStandbyDelayNs = AudioFlinger::mStandbyTimeInNsecs;
+ mStandbyDelayNs = getStandbyTimeInNanos();
// make sure standby delay is not too short when connected to an A2DP sink to avoid
// truncating audio when going to standby.
@@ -4631,7 +4710,7 @@
mLock.unlock();
// Unlock due to VibratorService will lock for this call and will
// call Tracks.mute/unmute which also require thread's lock.
- AudioFlinger::onExternalVibrationStop(track->getExternalVibration());
+ afutils::onExternalVibrationStop(track->getExternalVibration());
mLock.lock();
// When the track is stop, set the haptic intensity as MUTE
@@ -6180,7 +6259,7 @@
reconfig = true;
}
if (param.getInt(String8(AudioParameter::keyFormat), value) == NO_ERROR) {
- if (!AudioFlinger::isValidPcmSinkFormat(static_cast<audio_format_t>(value))) {
+ if (!isValidPcmSinkFormat(static_cast<audio_format_t>(value))) {
status = BAD_VALUE;
} else {
// no need to save value, since it's constant
@@ -6188,7 +6267,7 @@
}
}
if (param.getInt(String8(AudioParameter::keyChannels), value) == NO_ERROR) {
- if (!AudioFlinger::isValidPcmSinkChannelMask(static_cast<audio_channel_mask_t>(value))) {
+ if (!isValidPcmSinkChannelMask(static_cast<audio_channel_mask_t>(value))) {
status = BAD_VALUE;
} else {
// no need to save value, since it's constant
@@ -8656,7 +8735,7 @@
goto Exit;
}
if (maxSharedAudioHistoryMs < 0
- || maxSharedAudioHistoryMs > AudioFlinger::kMaxSharedAudioHistoryMs) {
+ || maxSharedAudioHistoryMs > kMaxSharedAudioHistoryMs) {
lStatus = BAD_VALUE;
goto Exit;
}
@@ -9480,7 +9559,7 @@
audio_input_flags_t flags = mInput->flags;
mediametrics::LogItem item(mThreadMetrics.getMetricsId());
item.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_READPARAMETERS)
- .set(AMEDIAMETRICS_PROP_ENCODING, formatToString(mFormat).c_str())
+ .set(AMEDIAMETRICS_PROP_ENCODING, IAfThreadBase::formatToString(mFormat).c_str())
.set(AMEDIAMETRICS_PROP_FLAGS, toString(flags).c_str())
.set(AMEDIAMETRICS_PROP_SAMPLERATE, (int32_t)mSampleRate)
.set(AMEDIAMETRICS_PROP_CHANNELMASK, (int32_t)mChannelMask)
@@ -9997,7 +10076,7 @@
audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
audio_io_handle_t io = mId;
- AttributionSourceState adjAttributionSource = AudioFlinger::checkAttributionSourcePackage(
+ const AttributionSourceState adjAttributionSource = afutils::checkAttributionSourcePackage(
client.attributionSource);
if (isOutput()) {
@@ -10219,7 +10298,7 @@
// TODO: make a readHalParameters call?
mediametrics::LogItem item(mThreadMetrics.getMetricsId());
item.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_READPARAMETERS)
- .set(AMEDIAMETRICS_PROP_ENCODING, formatToString(mFormat).c_str())
+ .set(AMEDIAMETRICS_PROP_ENCODING, IAfThreadBase::formatToString(mFormat).c_str())
.set(AMEDIAMETRICS_PROP_SAMPLERATE, (int32_t)mSampleRate)
.set(AMEDIAMETRICS_PROP_CHANNELMASK, (int32_t)mChannelMask)
.set(AMEDIAMETRICS_PROP_CHANNELCOUNT, (int32_t)mChannelCount)
@@ -10232,7 +10311,7 @@
(int32_t)mHapticChannelCount)
*/
.set(AMEDIAMETRICS_PROP_PREFIX_HAL AMEDIAMETRICS_PROP_ENCODING,
- formatToString(mHALFormat).c_str())
+ IAfThreadBase::formatToString(mHALFormat).c_str())
.set(AMEDIAMETRICS_PROP_PREFIX_HAL AMEDIAMETRICS_PROP_FRAMECOUNT,
(int32_t)mFrameCount) // sic - added HAL
.record();
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index a628867..474da8e 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -17,6 +17,25 @@
#pragma once
+// ADD_BATTERY_DATA AUDIO_WATCHDOG FAST_THREAD_STATISTICS STATE_QUEUE_DUMP TEE_SINK
+#include "Configuration.h"
+#include "IAfThread.h"
+#include "IAfTrack.h"
+
+#include <android-base/macros.h> // DISALLOW_COPY_AND_ASSIGN
+#include <android/os/IPowerManager.h>
+#include <afutils/AudioWatchdog.h>
+#include <afutils/NBAIO_Tee.h>
+#include <audio_utils/Balance.h>
+#include <audio_utils/SimpleLog.h>
+#include <datapath/ThreadMetrics.h>
+#include <fastpath/FastCapture.h>
+#include <fastpath/FastMixer.h>
+#include <mediautils/Synchronization.h>
+#include <mediautils/ThreadSnapshot.h>
+#include <timing/MonotonicFrameCounter.h>
+#include <utils/Log.h>
+
namespace android {
class AsyncCallbackThread;
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index 194a515..5708c61 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -17,6 +17,18 @@
#pragma once
+#include "Configuration.h" // TEE_SINK
+#include "IAfTrack.h"
+
+#include <afutils/NBAIO_Tee.h>
+#include <android-base/macros.h> // DISALLOW_COPY_AND_ASSIGN
+#include <datapath/TrackMetrics.h>
+#include <mediautils/BatteryNotifier.h>
+
+#include <atomic> // avoid transitive dependency
+#include <list> // avoid transitive dependency
+#include <optional> // avoid transitive dependency
+
namespace android {
// base for record and playback
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 257f9e4..1a00681 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -15,32 +15,33 @@
** limitations under the License.
*/
-
#define LOG_TAG "AudioFlinger"
//#define LOG_NDEBUG 0
#define ATRACE_TAG ATRACE_TAG_AUDIO
-#include "Configuration.h"
-#include <linux/futex.h>
-#include <math.h>
-#include <sys/syscall.h>
+#include "MmapTracks.h"
+#include "PlaybackTracks.h"
+#include "RecordTracks.h"
+
+#include "Client.h"
+#include "IAfEffect.h"
+#include "IAfThread.h"
+#include "ResamplerBufferProvider.h"
+
+#include <audio_utils/minifloat.h>
+#include <media/AudioValidator.h>
+#include <media/RecordBufferConverter.h>
+#include <media/nbaio/Pipe.h>
+#include <media/nbaio/PipeReader.h>
+#include <mediautils/ServiceUtilities.h>
+#include <mediautils/SharedMemoryAllocator.h>
+#include <private/media/AudioTrackShared.h>
#include <utils/Log.h>
#include <utils/Trace.h>
-#include <private/media/AudioTrackShared.h>
-
-#include "AudioFlinger.h"
-#include "TrackBase.h"
-#include "PlaybackTracks.h"
-#include "RecordTracks.h"
-#include "MmapTracks.h"
-
-#include <media/nbaio/Pipe.h>
-#include <media/nbaio/PipeReader.h>
-#include <media/AudioValidator.h>
-#include <media/RecordBufferConverter.h>
-#include <mediautils/ServiceUtilities.h>
-#include <audio_utils/minifloat.h>
+#include <linux/futex.h>
+#include <math.h>
+#include <sys/syscall.h>
// ----------------------------------------------------------------------------
diff --git a/services/audioflinger/afutils/Android.bp b/services/audioflinger/afutils/Android.bp
index 1580b8f..5e29ce9 100644
--- a/services/audioflinger/afutils/Android.bp
+++ b/services/audioflinger/afutils/Android.bp
@@ -39,18 +39,24 @@
"AudioWatchdog.cpp",
"BufLog.cpp",
"NBAIO_Tee.cpp",
+ "Permission.cpp",
"PropertyUtils.cpp",
"TypedLogger.cpp",
+ "Vibrator.cpp",
],
shared_libs: [
+ "framework-permission-aidl-cpp",
+ "libaudioclient_aidl_conversion",
"libaudioutils",
"libbase",
+ "libbinder",
"libcutils", // property_get_int32
"liblog",
"libnbaio",
"libnblog",
"libutils",
+ "libvibrator",
],
static_libs: [
diff --git a/services/audioflinger/afutils/DumpTryLock.h b/services/audioflinger/afutils/DumpTryLock.h
new file mode 100644
index 0000000..c185a68
--- /dev/null
+++ b/services/audioflinger/afutils/DumpTryLock.h
@@ -0,0 +1,31 @@
+/*
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <utils/Mutex.h>
+
+namespace android::afutils {
+
+inline bool dumpTryLock(Mutex& mutex)
+{
+ static constexpr int kDumpLockTimeoutNs = 1'000'000'000;
+ const status_t err = mutex.timedLock(kDumpLockTimeoutNs);
+ return err == NO_ERROR;
+}
+
+} // android::afutils
\ No newline at end of file
diff --git a/services/audioflinger/afutils/Permission.cpp b/services/audioflinger/afutils/Permission.cpp
new file mode 100644
index 0000000..35448e3
--- /dev/null
+++ b/services/audioflinger/afutils/Permission.cpp
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "Permission"
+//#define LOG_NDEBUG 0
+
+#include "Permission.h"
+
+#include <binder/PermissionController.h>
+#include <media/AidlConversionCppNdk.h>
+#include <utils/Log.h>
+
+namespace android::afutils {
+
+// TODO b/182392769: use attribution source util
+content::AttributionSourceState checkAttributionSourcePackage(
+ const content::AttributionSourceState& attributionSource) {
+ Vector<String16> packages;
+ PermissionController{}.getPackagesForUid(attributionSource.uid, packages);
+
+ content::AttributionSourceState checkedAttributionSource = attributionSource;
+ if (!attributionSource.packageName.has_value()
+ || attributionSource.packageName.value().size() == 0) {
+ if (!packages.isEmpty()) {
+ checkedAttributionSource.packageName =
+ std::move(legacy2aidl_String16_string(packages[0]).value());
+ }
+ } else {
+ const String16 opPackageLegacy = VALUE_OR_FATAL(
+ aidl2legacy_string_view_String16(attributionSource.packageName.value_or("")));
+ if (std::find_if(packages.begin(), packages.end(),
+ [&opPackageLegacy](const auto& package) {
+ return opPackageLegacy == package; }) == packages.end()) {
+ ALOGW("The package name(%s) provided does not correspond to the uid %d",
+ attributionSource.packageName.value_or("").c_str(), attributionSource.uid);
+ }
+ }
+ return checkedAttributionSource;
+}
+
+} // namespace android::afutils
diff --git a/services/audioflinger/afutils/Permission.h b/services/audioflinger/afutils/Permission.h
new file mode 100644
index 0000000..97c7ff9
--- /dev/null
+++ b/services/audioflinger/afutils/Permission.h
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android/content/AttributionSourceState.h>
+
+namespace android::afutils {
+
+content::AttributionSourceState checkAttributionSourcePackage(
+ const content::AttributionSourceState& attributionSource);
+
+} // namespace android::afutils
diff --git a/services/audioflinger/afutils/Vibrator.cpp b/services/audioflinger/afutils/Vibrator.cpp
new file mode 100644
index 0000000..25fcc6a
--- /dev/null
+++ b/services/audioflinger/afutils/Vibrator.cpp
@@ -0,0 +1,71 @@
+/*
+ *
+ * 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_TAG "AudioFlinger::Vibrator"
+//#define LOG_NDEBUG 0
+
+#include "Vibrator.h"
+
+#include <android/os/IExternalVibratorService.h>
+#include <binder/IServiceManager.h>
+#include <utils/Log.h>
+
+#include <mutex>
+
+namespace android::afutils {
+
+static sp<os::IExternalVibratorService> getExternalVibratorService() {
+ static std::mutex m;
+ static sp<os::IExternalVibratorService> sExternalVibratorService;
+
+ std::lock_guard l(m);
+ if (sExternalVibratorService == nullptr) {
+ const sp<IBinder> binder = defaultServiceManager()->getService(
+ String16("external_vibrator_service"));
+ if (binder != nullptr) {
+ sExternalVibratorService = interface_cast<os::IExternalVibratorService>(binder);
+ }
+ }
+ return sExternalVibratorService;
+}
+
+os::HapticScale onExternalVibrationStart(const sp<os::ExternalVibration>& externalVibration) {
+ const sp<os::IExternalVibratorService> evs = getExternalVibratorService();
+ if (evs != nullptr) {
+ int32_t ret;
+ binder::Status status = evs->onExternalVibrationStart(*externalVibration, &ret);
+ if (status.isOk()) {
+ ALOGD("%s, start external vibration with intensity as %d", __func__, ret);
+ return os::ExternalVibration::externalVibrationScaleToHapticScale(ret);
+ }
+ }
+ ALOGD("%s, start external vibration with intensity as MUTE due to %s",
+ __func__,
+ evs == nullptr ? "external vibration service not found"
+ : "error when querying intensity");
+ return os::HapticScale::MUTE;
+}
+
+void onExternalVibrationStop(const sp<os::ExternalVibration>& externalVibration) {
+ const sp<os::IExternalVibratorService> evs = getExternalVibratorService();
+ if (evs != nullptr) {
+ ALOGD("%s, stop external vibration", __func__);
+ evs->onExternalVibrationStop(*externalVibration);
+ }
+}
+
+} // namespace android::afutils
diff --git a/services/audioflinger/afutils/Vibrator.h b/services/audioflinger/afutils/Vibrator.h
new file mode 100644
index 0000000..4354872
--- /dev/null
+++ b/services/audioflinger/afutils/Vibrator.h
@@ -0,0 +1,29 @@
+/*
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <vibrator/ExternalVibration.h>
+#include <vibrator/ExternalVibrationUtils.h>
+
+namespace android::afutils {
+
+os::HapticScale onExternalVibrationStart(const sp<os::ExternalVibration>& externalVibration);
+
+void onExternalVibrationStop(const sp<os::ExternalVibration>& externalVibration);
+
+} // namespace android::afutils
diff --git a/services/audioflinger/datapath/AudioStreamIn.h b/services/audioflinger/datapath/AudioStreamIn.h
index 7b3a090..604a4e4 100644
--- a/services/audioflinger/datapath/AudioStreamIn.h
+++ b/services/audioflinger/datapath/AudioStreamIn.h
@@ -16,6 +16,7 @@
#pragma once
+#include "AudioHwDevice.h"
#include <media/audiohal/DeviceHalInterface.h>
#include <media/audiohal/StreamHalInterface.h>
diff --git a/services/audioflinger/datapath/ThreadMetrics.h b/services/audioflinger/datapath/ThreadMetrics.h
index 5493b3c..c643a57 100644
--- a/services/audioflinger/datapath/ThreadMetrics.h
+++ b/services/audioflinger/datapath/ThreadMetrics.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_AUDIO_THREADMETRICS_H
#define ANDROID_AUDIO_THREADMETRICS_H
+#include <media/MediaMetricsItem.h>
+
#include <mutex>
namespace android {
diff --git a/services/audioflinger/datapath/TrackMetrics.h b/services/audioflinger/datapath/TrackMetrics.h
index f3425df..2b44acb 100644
--- a/services/audioflinger/datapath/TrackMetrics.h
+++ b/services/audioflinger/datapath/TrackMetrics.h
@@ -20,6 +20,8 @@
#include <binder/IActivityManager.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
+#include <media/MediaMetricsItem.h>
+
#include <mutex>
namespace android {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 8f10c62..f1f2048 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -7835,6 +7835,9 @@
}
if (deviceTypes.empty()) {
deviceTypes = outputDesc->devices().types();
+ index = curves.getVolumeIndex(deviceTypes);
+ ALOGD("%s if deviceTypes is change from none to device %s, need get index %d",
+ __func__, dumpDeviceTypes(deviceTypes).c_str(), index);
}
if (curves.getVolumeIndexMin() < 0 || curves.getVolumeIndexMax() < 0) {
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 6d3c7a5..cbab6fa 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -5892,6 +5892,8 @@
" clear-stream-use-case-override clear the stream use case override\n"
" set-zoom-override <-1/0/1> enable or disable zoom override\n"
" Valid values -1: do not override, 0: override to OFF, 1: override to ZOOM\n"
+ " set-watchdog <VALUE> enables or disables the camera service watchdog\n"
+ " Valid values 0=disable, 1=enable\n"
" watch <start|stop|dump|print|clear> manages tag monitoring in connected clients\n"
" help print this message\n");
}