Merge "CCodec: don't update pipeline watcher if using input surface"
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 793cbf4..e584ffb 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -81,6 +81,7 @@
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libstagefright_xmlparser@1.0.so)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libstagefright_soft_*)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/vndk/libstagefright_soft_*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libaudiopolicyengineconfig*)
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
diff --git a/apex/Android.bp b/apex/Android.bp
index 9455290..0a9551d 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -42,6 +42,9 @@
},
key: "com.android.media.key",
certificate: ":com.android.media.certificate",
+
+ // Use a custom AndroidManifest.xml used for API targeting.
+ androidManifest: ":com.android.media-androidManifest",
}
apex {
@@ -50,14 +53,46 @@
defaults: ["com.android.media-defaults"],
}
+filegroup {
+ name: "com.android.media-androidManifest",
+ srcs: ["AndroidManifest-media.xml"],
+}
+
+filegroup {
+ name: "com.android.media.swcodec-androidManifest",
+ srcs: ["AndroidManifest-swcodec.xml"],
+}
+
apex_defaults {
name: "com.android.media.swcodec-defaults",
- native_shared_libs: [
- "libmedia_codecserviceregistrant",
+ binaries: [
+ "mediaswcodec",
+ ],
+ prebuilts: [
+ "com.android.media.swcodec-mediaswcodec.rc",
+ "com.android.media.swcodec-ld.config.txt",
+ "mediaswcodec.policy",
],
use_vendor: true,
key: "com.android.media.swcodec.key",
certificate: ":com.android.media.swcodec.certificate",
+
+ // Use a custom AndroidManifest.xml used for API targeting.
+ androidManifest: ":com.android.media.swcodec-androidManifest",
+}
+
+prebuilt_etc {
+ name: "com.android.media.swcodec-mediaswcodec.rc",
+ src: "mediaswcodec.rc",
+ filename: "init.rc",
+ installable: false,
+}
+
+prebuilt_etc {
+ name: "com.android.media.swcodec-ld.config.txt",
+ src: "ld.config.txt",
+ filename: "ld.config.txt",
+ installable: false,
}
apex {
diff --git a/apex/AndroidManifest-media.xml b/apex/AndroidManifest-media.xml
new file mode 100644
index 0000000..17d3f3a
--- /dev/null
+++ b/apex/AndroidManifest-media.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2017 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.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.media">
+ <!-- APEX does not have classes.dex -->
+ <application android:hasCode="false" />
+ <uses-sdk
+ android:minSdkVersion="28"
+ android:targetSdkVersion="28"
+ />
+</manifest>
diff --git a/apex/AndroidManifest-swcodec.xml b/apex/AndroidManifest-swcodec.xml
new file mode 100644
index 0000000..bd20dc0
--- /dev/null
+++ b/apex/AndroidManifest-swcodec.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2017 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.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.media.swcodec">
+ <!-- APEX does not have classes.dex -->
+ <application android:hasCode="false" />
+ <uses-sdk
+ android:minSdkVersion="28"
+ android:targetSdkVersion="28"
+ />
+</manifest>
diff --git a/apex/ld.config.txt b/apex/ld.config.txt
new file mode 100644
index 0000000..b342206
--- /dev/null
+++ b/apex/ld.config.txt
@@ -0,0 +1,74 @@
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Bionic loader config file for the media swcodec APEX.
+#
+# There are no versioned APEX paths here - this APEX module does not support
+# having several versions mounted.
+
+dir.swcodec = /apex/com.android.media.swcodec/bin/
+
+[swcodec]
+additional.namespaces = platform
+
+###############################################################################
+# "default" namespace
+#
+# This namespace is for the binaries and libraries on the swcodec APEX.
+###############################################################################
+
+namespace.default.isolated = true
+namespace.default.visible = true
+
+namespace.default.search.paths = /apex/com.android.media.swcodec/${LIB}
+namespace.default.asan.search.paths = /apex/com.android.media.swcodec/${LIB}
+
+# Keep the below in sync with "sphal" namespace in system's /etc/ld.config.txt
+# Codec2 has dependencies on some SP-hals (eg. android.hardware.graphics.mapper@2.0)
+# These are dlopen'ed by libvndksupport.so.
+namespace.default.search.paths += /odm/${LIB}
+namespace.default.search.paths += /vendor/${LIB}
+
+namespace.default.permitted.paths = /odm/${LIB}
+namespace.default.permitted.paths += /vendor/${LIB}
+namespace.default.permitted.paths += /vendor/${LIB}/hw
+namespace.default.permitted.paths += /system/vendor/${LIB}
+
+namespace.default.asan.search.paths += /data/asan/odm/${LIB}
+namespace.default.asan.search.paths += /odm/${LIB}
+namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
+namespace.default.asan.search.paths += /vendor/${LIB}
+
+namespace.default.asan.permitted.paths = /data/asan/odm/${LIB}
+namespace.default.asan.permitted.paths += /odm/${LIB}
+namespace.default.asan.permitted.paths += /data/asan/vendor/${LIB}
+namespace.default.asan.permitted.paths += /vendor/${LIB}
+
+namespace.default.links = platform
+
+# TODO: replace the following when apex has a way to auto-generate this list
+# namespace.default.link.platform.shared_libs = %LLNDK_LIBRARIES%
+# namespace.default.link.platform.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
+namespace.default.link.platform.shared_libs = libEGL.so:libGLESv1_CM.so:libGLESv2.so:libGLESv3.so:libRS.so:libandroid_net.so:libc.so:libclang_rt.asan-aarch64-android.so:libclang_rt.asan-arm-android.so:libclang_rt.hwasan-aarch64-android.so:libclang_rt.asan-i686-android.so:libclang_rt.asan-x86_64-android.so:libdl.so:libft2.so:liblog.so:libm.so:libmediandk.so:libnativewindow.so:libneuralnetworks.so:libsync.so:libvndksupport.so:libvulkan.so
+
+###############################################################################
+# "platform" namespace
+#
+# This namespace is for linking to LLNDK and ASAN libraries on the system.
+###############################################################################
+
+namespace.platform.isolated = true
+
+namespace.platform.search.paths = /system/${LIB}
+namespace.platform.asan.search.paths = /data/asan/system/${LIB}
+
+# /system/lib/libc.so, etc are symlinks to /apex/com.android.lib/lib/bionic/libc.so, etc.
+# Add /apex/... pat to the permitted paths because linker uses realpath(3)
+# to check the accessibility of the lib. We could add this to search.paths
+# instead but that makes the resolution of bionic libs be dependent on
+# the order of /system/lib and /apex/... in search.paths. If /apex/...
+# is after /system/lib, then /apex/... is never tried because libc.so
+# is always found in /system/lib but fails to pass the accessibility test
+# because of its realpath. It's better to not depend on the ordering if
+# possible.
+namespace.platform.permitted.paths = /apex/com.android.runtime/${LIB}/bionic
+namespace.platform.asan.permitted.paths = /apex/com.android.runtime/${LIB}/bionic
diff --git a/apex/mediaswcodec.rc b/apex/mediaswcodec.rc
new file mode 100644
index 0000000..d17481b
--- /dev/null
+++ b/apex/mediaswcodec.rc
@@ -0,0 +1,7 @@
+service media.swcodec /apex/com.android.media.swcodec/bin/mediaswcodec
+ class main
+ user mediacodec
+ group camera drmrpc mediadrm
+ override
+ ioprio rt 4
+ writepid /dev/cpuset/foreground/tasks
diff --git a/camera/OWNERS b/camera/OWNERS
index 18acfee..d6b95da 100644
--- a/camera/OWNERS
+++ b/camera/OWNERS
@@ -1,6 +1,8 @@
-cychen@google.com
epeev@google.com
etalvala@google.com
+jchowdhary@google.com
shuzhenwang@google.com
yinchiayeh@google.com
+# backup owner
+cychen@google.com
zhijunhe@google.com
diff --git a/camera/ndk/NdkCameraCaptureSession.cpp b/camera/ndk/NdkCameraCaptureSession.cpp
index ab796fb..1ac8482 100644
--- a/camera/ndk/NdkCameraCaptureSession.cpp
+++ b/camera/ndk/NdkCameraCaptureSession.cpp
@@ -105,7 +105,9 @@
if (session->isClosed()) {
ALOGE("%s: session %p is already closed", __FUNCTION__, session);
- *captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
+ if (captureSequenceId) {
+ *captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
+ }
return ACAMERA_ERROR_SESSION_CLOSED;
}
@@ -127,7 +129,9 @@
if (session->isClosed()) {
ALOGE("%s: session %p is already closed", __FUNCTION__, session);
- *captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
+ if (captureSequenceId) {
+ *captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
+ }
return ACAMERA_ERROR_SESSION_CLOSED;
}
@@ -149,7 +153,9 @@
if (session->isClosed()) {
ALOGE("%s: session %p is already closed", __FUNCTION__, session);
- *captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
+ if (captureSequenceId) {
+ *captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
+ }
return ACAMERA_ERROR_SESSION_CLOSED;
}
diff --git a/camera/ndk/NdkCameraDevice.cpp b/camera/ndk/NdkCameraDevice.cpp
index 98608da..09b85d5 100644
--- a/camera/ndk/NdkCameraDevice.cpp
+++ b/camera/ndk/NdkCameraDevice.cpp
@@ -78,7 +78,34 @@
ALOGE("%s: unknown template ID %d", __FUNCTION__, templateId);
return ACAMERA_ERROR_INVALID_PARAMETER;
}
- return device->createCaptureRequest(templateId, request);
+ return device->createCaptureRequest(templateId, nullptr /*physicalIdList*/, request);
+}
+
+EXPORT
+camera_status_t ACameraDevice_createCaptureRequest_withPhysicalIds(
+ const ACameraDevice* device,
+ ACameraDevice_request_template templateId,
+ const ACameraIdList* physicalCameraIdList,
+ ACaptureRequest** request) {
+ ATRACE_CALL();
+ if (device == nullptr || request == nullptr || physicalCameraIdList == nullptr) {
+ ALOGE("%s: invalid argument! device %p request %p, physicalCameraIdList %p",
+ __FUNCTION__, device, request, physicalCameraIdList);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ switch (templateId) {
+ case TEMPLATE_PREVIEW:
+ case TEMPLATE_STILL_CAPTURE:
+ case TEMPLATE_RECORD:
+ case TEMPLATE_VIDEO_SNAPSHOT:
+ case TEMPLATE_ZERO_SHUTTER_LAG:
+ case TEMPLATE_MANUAL:
+ break;
+ default:
+ ALOGE("%s: unknown template ID %d", __FUNCTION__, templateId);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ return device->createCaptureRequest(templateId, physicalCameraIdList, request);
}
EXPORT
diff --git a/camera/ndk/NdkCameraManager.cpp b/camera/ndk/NdkCameraManager.cpp
index 8742d9c..23d01ef 100644
--- a/camera/ndk/NdkCameraManager.cpp
+++ b/camera/ndk/NdkCameraManager.cpp
@@ -105,6 +105,60 @@
}
EXPORT
+camera_status_t ACameraManager_registerExtendedAvailabilityCallback(
+ ACameraManager* /*manager*/, const ACameraManager_ExtendedAvailabilityCallbacks *callback) {
+ ATRACE_CALL();
+ if (callback == nullptr) {
+ ALOGE("%s: invalid argument! callback is null!", __FUNCTION__);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ if ((callback->availabilityCallbacks.onCameraAvailable == nullptr) ||
+ (callback->availabilityCallbacks.onCameraUnavailable == nullptr) ||
+ (callback->onCameraAccessPrioritiesChanged == nullptr)) {
+ ALOGE("%s: invalid argument! callback %p, "
+ "onCameraAvailable %p, onCameraUnavailable %p onCameraAccessPrioritiesChanged %p",
+ __FUNCTION__, callback,
+ callback->availabilityCallbacks.onCameraAvailable,
+ callback->availabilityCallbacks.onCameraUnavailable,
+ callback->onCameraAccessPrioritiesChanged);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ auto reservedEntriesCount = sizeof(callback->reserved) / sizeof(callback->reserved[0]);
+ for (size_t i = 0; i < reservedEntriesCount; i++) {
+ if (callback->reserved[i] != nullptr) {
+ ALOGE("%s: invalid argument! callback reserved entries must be set to NULL",
+ __FUNCTION__);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ }
+ CameraManagerGlobal::getInstance().registerExtendedAvailabilityCallback(callback);
+ return ACAMERA_OK;
+}
+
+EXPORT
+camera_status_t ACameraManager_unregisterExtendedAvailabilityCallback(
+ ACameraManager* /*manager*/, const ACameraManager_ExtendedAvailabilityCallbacks *callback) {
+ ATRACE_CALL();
+ if (callback == nullptr) {
+ ALOGE("%s: invalid argument! callback is null!", __FUNCTION__);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ if ((callback->availabilityCallbacks.onCameraAvailable == nullptr) ||
+ (callback->availabilityCallbacks.onCameraUnavailable == nullptr) ||
+ (callback->onCameraAccessPrioritiesChanged == nullptr)) {
+ ALOGE("%s: invalid argument! callback %p, "
+ "onCameraAvailable %p, onCameraUnavailable %p onCameraAccessPrioritiesChanged %p",
+ __FUNCTION__, callback,
+ callback->availabilityCallbacks.onCameraAvailable,
+ callback->availabilityCallbacks.onCameraUnavailable,
+ callback->onCameraAccessPrioritiesChanged);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ CameraManagerGlobal::getInstance().unregisterExtendedAvailabilityCallback(callback);
+ return ACAMERA_OK;
+}
+
+EXPORT
camera_status_t ACameraManager_getCameraCharacteristics(
ACameraManager* mgr, const char* cameraId, ACameraMetadata** chars){
ATRACE_CALL();
diff --git a/camera/ndk/NdkCaptureRequest.cpp b/camera/ndk/NdkCaptureRequest.cpp
index c64de3e..87de4a9 100644
--- a/camera/ndk/NdkCaptureRequest.cpp
+++ b/camera/ndk/NdkCaptureRequest.cpp
@@ -98,6 +98,27 @@
}
EXPORT
+camera_status_t ACaptureRequest_getConstEntry_physicalCamera(
+ const ACaptureRequest* req, const char* physicalId,
+ uint32_t tag, ACameraMetadata_const_entry* entry) {
+ ATRACE_CALL();
+ if (req == nullptr || entry == nullptr || physicalId == nullptr) {
+ ALOGE("%s: invalid argument! req %p, tag 0x%x, entry %p, physicalId %p",
+ __FUNCTION__, req, tag, entry, physicalId);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+
+ const auto& physicalSettings = req->physicalSettings.find(physicalId);
+ if (physicalSettings == req->physicalSettings.end()) {
+ ALOGE("%s: Failed to find metadata for physical camera id %s",
+ __FUNCTION__, physicalId);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+
+ return physicalSettings->second->getConstEntry(tag, entry);
+}
+
+EXPORT
camera_status_t ACaptureRequest_getAllTags(
const ACaptureRequest* req, /*out*/int32_t* numTags, /*out*/const uint32_t** tags) {
ATRACE_CALL();
@@ -131,6 +152,34 @@
#undef SET_ENTRY
+#define SET_PHYSICAL_ENTRY(NAME,NDK_TYPE) \
+EXPORT \
+camera_status_t ACaptureRequest_setEntry_physicalCamera_##NAME( \
+ ACaptureRequest* req, const char* physicalId, uint32_t tag, \
+ uint32_t count, const NDK_TYPE* data) { \
+ ATRACE_CALL(); \
+ if (req == nullptr || (count > 0 && data == nullptr) || physicalId == nullptr) { \
+ ALOGE("%s: invalid argument! req %p, tag 0x%x, count %d, data 0x%p, physicalId %p", \
+ __FUNCTION__, req, tag, count, data, physicalId); \
+ return ACAMERA_ERROR_INVALID_PARAMETER; \
+ } \
+ if (req->physicalSettings.find(physicalId) == req->physicalSettings.end()) { \
+ ALOGE("%s: Failed to find metadata for physical camera id %s", \
+ __FUNCTION__, physicalId); \
+ return ACAMERA_ERROR_INVALID_PARAMETER; \
+ } \
+ return req->physicalSettings[physicalId]->update(tag, count, data); \
+}
+
+SET_PHYSICAL_ENTRY(u8,uint8_t)
+SET_PHYSICAL_ENTRY(i32,int32_t)
+SET_PHYSICAL_ENTRY(float,float)
+SET_PHYSICAL_ENTRY(double,double)
+SET_PHYSICAL_ENTRY(i64,int64_t)
+SET_PHYSICAL_ENTRY(rational,ACameraMetadata_rational)
+
+#undef SET_PHYSICAL_ENTRY
+
EXPORT
void ACaptureRequest_free(ACaptureRequest* request) {
ATRACE_CALL();
@@ -138,6 +187,7 @@
return;
}
request->settings.clear();
+ request->physicalSettings.clear();
delete request->targets;
delete request;
return;
@@ -174,6 +224,9 @@
ACaptureRequest* pRequest = new ACaptureRequest();
pRequest->settings = new ACameraMetadata(*(src->settings));
+ for (const auto& entry : src->physicalSettings) {
+ pRequest->physicalSettings[entry.first] = new ACameraMetadata(*(entry.second));
+ }
pRequest->targets = new ACameraOutputTargets();
*(pRequest->targets) = *(src->targets);
pRequest->context = src->context;
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index d8a5765..5e4fcd0 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -76,7 +76,7 @@
__FUNCTION__, strerror(-err), err);
setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
}
- mHandler = new CallbackHandler();
+ mHandler = new CallbackHandler(id);
mCbLooper->registerHandler(mHandler);
const CameraMetadata& metadata = mChars->getInternalData();
@@ -97,6 +97,14 @@
mShadingMapSize[0] = entry.data.i32[0];
mShadingMapSize[1] = entry.data.i32[1];
}
+
+ size_t physicalIdCnt = 0;
+ const char*const* physicalCameraIds;
+ if (mChars->isLogicalMultiCamera(&physicalIdCnt, &physicalCameraIds)) {
+ for (size_t i = 0; i < physicalIdCnt; i++) {
+ mPhysicalIds.push_back(physicalCameraIds[i]);
+ }
+ }
}
// Device close implementaiton
@@ -129,8 +137,29 @@
camera_status_t
CameraDevice::createCaptureRequest(
ACameraDevice_request_template templateId,
+ const ACameraIdList* physicalIdList,
ACaptureRequest** request) const {
Mutex::Autolock _l(mDeviceLock);
+
+ if (physicalIdList != nullptr) {
+ if (physicalIdList->numCameras > static_cast<int>(mPhysicalIds.size())) {
+ ALOGE("%s: physicalIdList size %d exceeds number of available physical cameras %zu",
+ __FUNCTION__, physicalIdList->numCameras, mPhysicalIds.size());
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ for (auto i = 0; i < physicalIdList->numCameras; i++) {
+ if (physicalIdList->cameraIds[i] == nullptr) {
+ ALOGE("%s: physicalId is null!", __FUNCTION__);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ if (mPhysicalIds.end() == std::find(
+ mPhysicalIds.begin(), mPhysicalIds.end(), physicalIdList->cameraIds[i])) {
+ ALOGE("%s: Invalid physicalId %s!", __FUNCTION__, physicalIdList->cameraIds[i]);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ }
+ }
+
camera_status_t ret = checkCameraClosedOrErrorLocked();
if (ret != ACAMERA_OK) {
return ret;
@@ -151,6 +180,12 @@
}
ACaptureRequest* outReq = new ACaptureRequest();
outReq->settings = new ACameraMetadata(rawRequest.release(), ACameraMetadata::ACM_REQUEST);
+ if (physicalIdList != nullptr) {
+ for (auto i = 0; i < physicalIdList->numCameras; i++) {
+ outReq->physicalSettings.emplace(physicalIdList->cameraIds[i],
+ new ACameraMetadata(*(outReq->settings)));
+ }
+ }
outReq->targets = new ACameraOutputTargets();
*request = outReq;
return ACAMERA_OK;
@@ -275,8 +310,12 @@
const ACaptureRequest* request, /*out*/sp<CaptureRequest>& outReq) {
camera_status_t ret;
sp<CaptureRequest> req(new CaptureRequest());
- req->mPhysicalCameraSettings.push_back({std::string(mCameraId.string()),
+ req->mPhysicalCameraSettings.push_back({getId(),
request->settings->getInternalData()});
+ for (auto& entry : request->physicalSettings) {
+ req->mPhysicalCameraSettings.push_back({entry.first,
+ entry.second->getInternalData()});
+ }
req->mIsReprocess = false; // NDK does not support reprocessing yet
req->mContext = request->context;
req->mSurfaceConverted = true; // set to true, and fill in stream/surface idx to speed up IPC
@@ -320,10 +359,17 @@
}
ACaptureRequest*
-CameraDevice::allocateACaptureRequest(sp<CaptureRequest>& req) {
+CameraDevice::allocateACaptureRequest(sp<CaptureRequest>& req, const std::string& deviceId) {
ACaptureRequest* pRequest = new ACaptureRequest();
- CameraMetadata clone = req->mPhysicalCameraSettings.begin()->settings;
- pRequest->settings = new ACameraMetadata(clone.release(), ACameraMetadata::ACM_REQUEST);
+ for (auto& entry : req->mPhysicalCameraSettings) {
+ CameraMetadata clone = entry.settings;
+ if (entry.id == deviceId) {
+ pRequest->settings = new ACameraMetadata(clone.release(), ACameraMetadata::ACM_REQUEST);
+ } else {
+ pRequest->physicalSettings.emplace(entry.id,
+ new ACameraMetadata(clone.release(), ACameraMetadata::ACM_REQUEST));
+ }
+ }
pRequest->targets = new ACameraOutputTargets();
for (size_t i = 0; i < req->mSurfaceList.size(); i++) {
ANativeWindow* anw = static_cast<ANativeWindow*>(req->mSurfaceList[i].get());
@@ -340,6 +386,7 @@
return;
}
req->settings.clear();
+ req->physicalSettings.clear();
delete req->targets;
delete req;
}
@@ -786,6 +833,9 @@
return;
}
+CameraDevice::CallbackHandler::CallbackHandler(const char* id) : mId(id) {
+}
+
void CameraDevice::CallbackHandler::onMessageReceived(
const sp<AMessage> &msg) {
switch (msg->what()) {
@@ -927,7 +977,7 @@
ALOGE("%s: Cannot find timestamp!", __FUNCTION__);
return;
}
- ACaptureRequest* request = allocateACaptureRequest(requestSp);
+ ACaptureRequest* request = allocateACaptureRequest(requestSp, mId);
(*onStart)(context, session.get(), request, timestamp);
freeACaptureRequest(request);
break;
@@ -950,7 +1000,7 @@
return;
}
sp<ACameraMetadata> result(static_cast<ACameraMetadata*>(obj.get()));
- ACaptureRequest* request = allocateACaptureRequest(requestSp);
+ ACaptureRequest* request = allocateACaptureRequest(requestSp, mId);
(*onResult)(context, session.get(), request, result.get());
freeACaptureRequest(request);
break;
@@ -1006,7 +1056,7 @@
physicalMetadataCopyPtrs.push_back(physicalMetadataCopy[i].get());
}
- ACaptureRequest* request = allocateACaptureRequest(requestSp);
+ ACaptureRequest* request = allocateACaptureRequest(requestSp, mId);
(*onResult)(context, session.get(), request, result.get(),
physicalResultInfo.size(), physicalCameraIdPtrs.data(),
physicalMetadataCopyPtrs.data());
@@ -1034,7 +1084,7 @@
static_cast<CameraCaptureFailure*>(obj.get()));
ACameraCaptureFailure* failure =
static_cast<ACameraCaptureFailure*>(failureSp.get());
- ACaptureRequest* request = allocateACaptureRequest(requestSp);
+ ACaptureRequest* request = allocateACaptureRequest(requestSp, mId);
(*onFail)(context, session.get(), request, failure);
freeACaptureRequest(request);
break;
@@ -1111,7 +1161,7 @@
return;
}
- ACaptureRequest* request = allocateACaptureRequest(requestSp);
+ ACaptureRequest* request = allocateACaptureRequest(requestSp, mId);
(*onBufferLost)(context, session.get(), request, anw, frameNumber);
freeACaptureRequest(request);
break;
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h
index d0f363b..103efd5 100644
--- a/camera/ndk/impl/ACameraDevice.h
+++ b/camera/ndk/impl/ACameraDevice.h
@@ -68,6 +68,7 @@
camera_status_t createCaptureRequest(
ACameraDevice_request_template templateId,
+ const ACameraIdList* physicalIdList,
ACaptureRequest** request) const;
camera_status_t createCaptureSession(
@@ -145,7 +146,8 @@
camera_status_t allocateCaptureRequest(
const ACaptureRequest* request, sp<CaptureRequest>& outReq);
- static ACaptureRequest* allocateACaptureRequest(sp<CaptureRequest>& req);
+ static ACaptureRequest* allocateACaptureRequest(sp<CaptureRequest>& req,
+ const std::string& deviceId);
static void freeACaptureRequest(ACaptureRequest*);
// only For session to hold device lock
@@ -230,9 +232,11 @@
class CallbackHandler : public AHandler {
public:
+ explicit CallbackHandler(const char* id);
void onMessageReceived(const sp<AMessage> &msg) override;
private:
+ std::string mId;
// This handler will cache all capture session sp until kWhatCleanUpSessions
// is processed. This is used to guarantee the last session reference is always
// being removed in callback thread without holding camera device lock
@@ -327,6 +331,7 @@
// Misc variables
int32_t mShadingMapSize[2]; // const after constructor
int32_t mPartialResultCount; // const after constructor
+ std::vector<std::string> mPhysicalIds; // const after constructor
};
@@ -351,8 +356,9 @@
camera_status_t createCaptureRequest(
ACameraDevice_request_template templateId,
+ const ACameraIdList* physicalCameraIdList,
ACaptureRequest** request) const {
- return mDevice->createCaptureRequest(templateId, request);
+ return mDevice->createCaptureRequest(templateId, physicalCameraIdList, request);
}
camera_status_t createCaptureSession(
diff --git a/camera/ndk/impl/ACameraManager.cpp b/camera/ndk/impl/ACameraManager.cpp
index 7d6ecac..9d40fd7 100644
--- a/camera/ndk/impl/ACameraManager.cpp
+++ b/camera/ndk/impl/ACameraManager.cpp
@@ -193,6 +193,20 @@
}
}
+void CameraManagerGlobal::registerExtendedAvailabilityCallback(
+ const ACameraManager_ExtendedAvailabilityCallbacks *callback) {
+ Mutex::Autolock _l(mLock);
+ Callback cb(callback);
+ mCallbacks.insert(cb);
+}
+
+void CameraManagerGlobal::unregisterExtendedAvailabilityCallback(
+ const ACameraManager_ExtendedAvailabilityCallbacks *callback) {
+ Mutex::Autolock _l(mLock);
+ Callback cb(callback);
+ mCallbacks.erase(cb);
+}
+
void CameraManagerGlobal::registerAvailabilityCallback(
const ACameraManager_AvailabilityCallbacks *callback) {
Mutex::Autolock _l(mLock);
@@ -289,12 +303,40 @@
(*cb)(context, cameraId.c_str());
break;
}
+ case kWhatSendSingleAccessCallback:
+ {
+ ACameraManager_AccessPrioritiesChangedCallback cb;
+ void* context;
+ AString cameraId;
+ bool found = msg->findPointer(kCallbackFpKey, (void**) &cb);
+ if (!found) {
+ ALOGE("%s: Cannot find camera callback fp!", __FUNCTION__);
+ return;
+ }
+ found = msg->findPointer(kContextKey, &context);
+ if (!found) {
+ ALOGE("%s: Cannot find callback context!", __FUNCTION__);
+ return;
+ }
+ (*cb)(context);
+ break;
+ }
default:
ALOGE("%s: unknown message type %d", __FUNCTION__, msg->what());
break;
}
}
+binder::Status CameraManagerGlobal::CameraServiceListener::onCameraAccessPrioritiesChanged() {
+ sp<CameraManagerGlobal> cm = mCameraManager.promote();
+ if (cm != nullptr) {
+ cm->onCameraAccessPrioritiesChanged();
+ } else {
+ ALOGE("Cannot deliver camera access priority callback. Global camera manager died");
+ }
+ return binder::Status::ok();
+}
+
binder::Status CameraManagerGlobal::CameraServiceListener::onStatusChanged(
int32_t status, const String16& cameraId) {
sp<CameraManagerGlobal> cm = mCameraManager.promote();
@@ -306,6 +348,19 @@
return binder::Status::ok();
}
+void CameraManagerGlobal::onCameraAccessPrioritiesChanged() {
+ Mutex::Autolock _l(mLock);
+ for (auto cb : mCallbacks) {
+ sp<AMessage> msg = new AMessage(kWhatSendSingleAccessCallback, mHandler);
+ ACameraManager_AccessPrioritiesChangedCallback cbFp = cb.mAccessPriorityChanged;
+ if (cbFp != nullptr) {
+ msg->setPointer(kCallbackFpKey, (void *) cbFp);
+ msg->setPointer(kContextKey, cb.mContext);
+ msg->post();
+ }
+ }
+}
+
void CameraManagerGlobal::onStatusChanged(
int32_t status, const String8& cameraId) {
Mutex::Autolock _l(mLock);
diff --git a/camera/ndk/impl/ACameraManager.h b/camera/ndk/impl/ACameraManager.h
index c3407f0..8c1da36 100644
--- a/camera/ndk/impl/ACameraManager.h
+++ b/camera/ndk/impl/ACameraManager.h
@@ -54,6 +54,11 @@
void unregisterAvailabilityCallback(
const ACameraManager_AvailabilityCallbacks *callback);
+ void registerExtendedAvailabilityCallback(
+ const ACameraManager_ExtendedAvailabilityCallbacks* callback);
+ void unregisterExtendedAvailabilityCallback(
+ const ACameraManager_ExtendedAvailabilityCallbacks* callback);
+
/**
* Return camera IDs that support camera2
*/
@@ -86,10 +91,7 @@
return binder::Status::ok();
}
- // Access priority API not implemented yet
- virtual binder::Status onCameraAccessPrioritiesChanged() {
- return binder::Status::ok();
- }
+ virtual binder::Status onCameraAccessPrioritiesChanged();
private:
const wp<CameraManagerGlobal> mCameraManager;
@@ -101,11 +103,19 @@
explicit Callback(const ACameraManager_AvailabilityCallbacks *callback) :
mAvailable(callback->onCameraAvailable),
mUnavailable(callback->onCameraUnavailable),
+ mAccessPriorityChanged(nullptr),
mContext(callback->context) {}
+ explicit Callback(const ACameraManager_ExtendedAvailabilityCallbacks *callback) :
+ mAvailable(callback->availabilityCallbacks.onCameraAvailable),
+ mUnavailable(callback->availabilityCallbacks.onCameraUnavailable),
+ mAccessPriorityChanged(callback->onCameraAccessPrioritiesChanged),
+ mContext(callback->availabilityCallbacks.context) {}
+
bool operator == (const Callback& other) const {
return (mAvailable == other.mAvailable &&
mUnavailable == other.mUnavailable &&
+ mAccessPriorityChanged == other.mAccessPriorityChanged &&
mContext == other.mContext);
}
bool operator != (const Callback& other) const {
@@ -114,6 +124,9 @@
bool operator < (const Callback& other) const {
if (*this == other) return false;
if (mContext != other.mContext) return mContext < other.mContext;
+ if (mAccessPriorityChanged != other.mAccessPriorityChanged) {
+ return mAccessPriorityChanged < other.mAccessPriorityChanged;
+ }
if (mAvailable != other.mAvailable) return mAvailable < other.mAvailable;
return mUnavailable < other.mUnavailable;
}
@@ -122,13 +135,15 @@
}
ACameraManager_AvailabilityCallback mAvailable;
ACameraManager_AvailabilityCallback mUnavailable;
+ ACameraManager_AccessPrioritiesChangedCallback mAccessPriorityChanged;
void* mContext;
};
std::set<Callback> mCallbacks;
// definition of handler and message
enum {
- kWhatSendSingleCallback
+ kWhatSendSingleCallback,
+ kWhatSendSingleAccessCallback,
};
static const char* kCameraIdKey;
static const char* kCallbackFpKey;
@@ -141,6 +156,7 @@
sp<CallbackHandler> mHandler;
sp<ALooper> mCbLooper; // Looper thread where callbacks actually happen on
+ void onCameraAccessPrioritiesChanged();
void onStatusChanged(int32_t status, const String8& cameraId);
void onStatusChangedLocked(int32_t status, const String8& cameraId);
// Utils for status
diff --git a/camera/ndk/impl/ACameraMetadata.cpp b/camera/ndk/impl/ACameraMetadata.cpp
index 359eaed..d832deb 100644
--- a/camera/ndk/impl/ACameraMetadata.cpp
+++ b/camera/ndk/impl/ACameraMetadata.cpp
@@ -215,7 +215,7 @@
const int STREAM_HEIGHT_OFFSET = 2;
const int STREAM_IS_INPUT_OFFSET = 3;
camera_metadata_entry entry = mData.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
- if (entry.count == 0 || entry.count % 4 || entry.type != TYPE_INT32) {
+ if (entry.count > 0 && (entry.count % 4 || entry.type != TYPE_INT32)) {
ALOGE("%s: malformed available stream configuration key! count %zu, type %d",
__FUNCTION__, entry.count, entry.type);
return;
@@ -243,9 +243,17 @@
filteredStreamConfigs.push_back(isInput);
}
- mData.update(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, filteredStreamConfigs);
+ if (filteredStreamConfigs.size() > 0) {
+ mData.update(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, filteredStreamConfigs);
+ }
entry = mData.find(ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS);
+ if (entry.count > 0 && (entry.count % 4 || entry.type != TYPE_INT32)) {
+ ALOGE("%s: malformed available depth stream configuration key! count %zu, type %d",
+ __FUNCTION__, entry.count, entry.type);
+ return;
+ }
+
Vector<int32_t> filteredDepthStreamConfigs;
filteredDepthStreamConfigs.setCapacity(entry.count);
@@ -270,7 +278,11 @@
filteredDepthStreamConfigs.push_back(height);
filteredDepthStreamConfigs.push_back(isInput);
}
- mData.update(ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS, filteredDepthStreamConfigs);
+
+ if (filteredDepthStreamConfigs.size() > 0) {
+ mData.update(ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS,
+ filteredDepthStreamConfigs);
+ }
entry = mData.find(ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS);
Vector<int32_t> filteredHeicStreamConfigs;
diff --git a/camera/ndk/impl/ACaptureRequest.h b/camera/ndk/impl/ACaptureRequest.h
index 5c82ab7..2ffcafe 100644
--- a/camera/ndk/impl/ACaptureRequest.h
+++ b/camera/ndk/impl/ACaptureRequest.h
@@ -18,6 +18,7 @@
#include <camera/NdkCaptureRequest.h>
#include <set>
+#include <unordered_map>
using namespace android;
@@ -59,7 +60,8 @@
return ACAMERA_OK;
}
- sp<ACameraMetadata> settings;
+ sp<ACameraMetadata> settings;
+ std::unordered_map<std::string, sp<ACameraMetadata>> physicalSettings;
ACameraOutputTargets* targets;
void* context;
};
diff --git a/camera/ndk/include/camera/NdkCameraDevice.h b/camera/ndk/include/camera/NdkCameraDevice.h
index 26af4f8..cedf83a 100644
--- a/camera/ndk/include/camera/NdkCameraDevice.h
+++ b/camera/ndk/include/camera/NdkCameraDevice.h
@@ -53,6 +53,17 @@
*/
typedef struct ACameraDevice ACameraDevice;
+/**
+ * Struct to hold list of camera device Ids. This can refer to either the Ids
+ * of connected camera devices returned from {@link ACameraManager_getCameraIdList},
+ * or the physical camera Ids passed into
+ * {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ */
+typedef struct ACameraIdList {
+ int numCameras; ///< Number of camera device Ids
+ const char** cameraIds; ///< list of camera device Ids
+} ACameraIdList;
+
/// Enum for ACameraDevice_ErrorStateCallback error code
enum {
/**
@@ -793,6 +804,47 @@
ACameraWindowType* anw, const char* physicalId,
/*out*/ACaptureSessionOutput** output) __INTRODUCED_IN(29);
+/**
+ * Create a logical multi-camera ACaptureRequest for capturing images, initialized with template
+ * for a target use case, with the ability to specify physical camera settings.
+ *
+ * <p>The settings are chosen to be the best options for this camera device,
+ * so it is not recommended to reuse the same request for a different camera device.</p>
+ *
+ * <p>Note that for all keys in physical camera settings, only the keys
+ * advertised in ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS are
+ * applicable. All other keys are ignored by the camera device.</p>
+ *
+ * @param device the camera device of interest
+ * @param templateId the type of capture request to be created.
+ * See {@link ACameraDevice_request_template}.
+ * @param physicalIdList The list of physical camera Ids that can be used to
+ * customize the request for a specific physical camera.
+ * @param request the output request will be stored here if the method call succeeds.
+ *
+ * @return <ul>
+ * <li>{@link ACAMERA_OK} if the method call succeeds. The created capture request will be
+ * filled in request argument.</li>
+ * <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if device, physicalIdList, or request is
+ * NULL, templateId is undefined or camera device does not support
+ * requested template, or if some Ids in physicalIdList isn't a
+ * valid physical camera backing the current camera device.</li>
+ * <li>{@link ACAMERA_ERROR_CAMERA_DISCONNECTED} if the camera device is closed.</li>
+ * <li>{@link ACAMERA_ERROR_CAMERA_DEVICE} if the camera device encounters fatal error.</li>
+ * <li>{@link ACAMERA_ERROR_CAMERA_SERVICE} if the camera service encounters fatal error.</li>
+ * <li>{@link ACAMERA_ERROR_UNKNOWN} if the method fails for some other reasons.</li></ul>
+ *
+ * @see TEMPLATE_PREVIEW
+ * @see TEMPLATE_RECORD
+ * @see TEMPLATE_STILL_CAPTURE
+ * @see TEMPLATE_VIDEO_SNAPSHOT
+ * @see TEMPLATE_MANUAL
+ */
+camera_status_t ACameraDevice_createCaptureRequest_withPhysicalIds(
+ const ACameraDevice* device, ACameraDevice_request_template templateId,
+ const ACameraIdList* physicalIdList,
+ /*out*/ACaptureRequest** request) __INTRODUCED_IN(29);
+
#endif /* __ANDROID_API__ >= 29 */
__END_DECLS
diff --git a/camera/ndk/include/camera/NdkCameraManager.h b/camera/ndk/include/camera/NdkCameraManager.h
index ea76738..136a497 100644
--- a/camera/ndk/include/camera/NdkCameraManager.h
+++ b/camera/ndk/include/camera/NdkCameraManager.h
@@ -74,12 +74,6 @@
*/
void ACameraManager_delete(ACameraManager* manager) __INTRODUCED_IN(24);
-/// Struct to hold list of camera devices
-typedef struct ACameraIdList {
- int numCameras; ///< Number of connected camera devices
- const char** cameraIds; ///< list of identifier of connected camera devices
-} ACameraIdList;
-
/**
* Create a list of currently connected camera devices, including
* cameras that may be in use by other camera API clients.
@@ -278,6 +272,105 @@
#endif /* __ANDROID_API__ >= 24 */
+#if __ANDROID_API__ >= 29
+
+/**
+ * Definition of camera access permission change callback.
+ *
+ * <p>Notification that camera access priorities have changed and the camera may
+ * now be openable. An application that was previously denied camera access due to
+ * a higher-priority user already using the camera, or that was disconnected from an
+ * active camera session due to a higher-priority user trying to open the camera,
+ * should try to open the camera again if it still wants to use it. Note that
+ * multiple applications may receive this callback at the same time, and only one of
+ * them will succeed in opening the camera in practice, depending on exact access
+ * priority levels and timing. This method is useful in cases where multiple
+ * applications may be in the resumed state at the same time, and the user switches
+ * focus between them, or if the current camera-using application moves between
+ * full-screen and Picture-in-Picture (PiP) states. In such cases, the camera
+ * available/unavailable callbacks will not be invoked, but another application may
+ * now have higher priority for camera access than the current camera-using
+ * application.</p>
+
+ * @param context The optional application context provided by user in
+ * {@link ACameraManager_AvailabilityListener}.
+ */
+typedef void (*ACameraManager_AccessPrioritiesChangedCallback)(void* context);
+
+/**
+ * A listener for camera devices becoming available/unavailable to open or when
+ * the camera access permissions change.
+ *
+ * <p>Cameras become available when they are no longer in use, or when a new
+ * removable camera is connected. They become unavailable when some
+ * application or service starts using a camera, or when a removable camera
+ * is disconnected.</p>
+ *
+ * @see ACameraManager_registerExtendedAvailabilityCallback
+ */
+typedef struct ACameraManager_ExtendedAvailabilityListener {
+ ///
+ ACameraManager_AvailabilityCallbacks availabilityCallbacks;
+
+ /// Called when there is camera access permission change
+ ACameraManager_AccessPrioritiesChangedCallback onCameraAccessPrioritiesChanged;
+
+ /// Reserved for future use, please ensure that all entries are set to NULL
+ void *reserved[6];
+} ACameraManager_ExtendedAvailabilityCallbacks;
+
+/**
+ * Register camera extended availability callbacks.
+ *
+ * <p>onCameraUnavailable will be called whenever a camera device is opened by any camera API
+ * client. Other camera API clients may still be able to open such a camera device, evicting the
+ * existing client if they have higher priority than the existing client of a camera device.
+ * See {@link ACameraManager_openCamera} for more details.</p>
+ *
+ * <p>The callbacks will be called on a dedicated thread shared among all ACameraManager
+ * instances.</p>
+ *
+ * <p>Since this callback will be registered with the camera service, remember to unregister it
+ * once it is no longer needed; otherwise the callback will continue to receive events
+ * indefinitely and it may prevent other resources from being released. Specifically, the
+ * callbacks will be invoked independently of the general activity lifecycle and independently
+ * of the state of individual ACameraManager instances.</p>
+ *
+ * @param manager the {@link ACameraManager} of interest.
+ * @param callback the {@link ACameraManager_ExtendedAvailabilityCallbacks} to be registered.
+ *
+ * @return <ul>
+ * <li>{@link ACAMERA_OK} if the method call succeeds.</li>
+ * <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if manager or callback is NULL, or
+ * {ACameraManager_ExtendedAvailabilityCallbacks#onCameraAccessPrioritiesChanged}
+ * or {ACameraManager_AvailabilityCallbacks#onCameraAvailable} or
+ * {ACameraManager_AvailabilityCallbacks#onCameraUnavailable} is NULL.</li></ul>
+ */
+camera_status_t ACameraManager_registerExtendedAvailabilityCallback(
+ ACameraManager* manager,
+ const ACameraManager_ExtendedAvailabilityCallbacks* callback) __INTRODUCED_IN(29);
+
+/**
+ * Unregister camera extended availability callbacks.
+ *
+ * <p>Removing a callback that isn't registered has no effect.</p>
+ *
+ * @param manager the {@link ACameraManager} of interest.
+ * @param callback the {@link ACameraManager_ExtendedAvailabilityCallbacks} to be unregistered.
+ *
+ * @return <ul>
+ * <li>{@link ACAMERA_OK} if the method call succeeds.</li>
+ * <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if callback,
+ * {ACameraManager_ExtendedAvailabilityCallbacks#onCameraAccessPrioritiesChanged}
+ * or {ACameraManager_AvailabilityCallbacks#onCameraAvailable} or
+ * {ACameraManager_AvailabilityCallbacks#onCameraUnavailable} is NULL.</li></ul>
+ */
+camera_status_t ACameraManager_unregisterExtendedAvailabilityCallback(
+ ACameraManager* manager,
+ const ACameraManager_ExtendedAvailabilityCallbacks* callback) __INTRODUCED_IN(29);
+
+#endif /* __ANDROID_API__ >= 29 */
+
__END_DECLS
#endif /* _NDK_CAMERA_MANAGER_H */
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index b200abf..acf6999 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -3046,6 +3046,28 @@
*/
ACAMERA_REQUEST_AVAILABLE_SESSION_KEYS = // int32[n]
ACAMERA_REQUEST_START + 16,
+ /**
+ * <p>A subset of the available request keys that can be overridden for
+ * physical devices backing a logical multi-camera.</p>
+ *
+ * <p>Type: int32[n]</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>This is a subset of ACAMERA_REQUEST_AVAILABLE_REQUEST_KEYS which contains a list
+ * of keys that can be overridden using <a href="https://developer.android.com/reference/CaptureRequest/Builder.html#setPhysicalCameraKey">Builder#setPhysicalCameraKey</a>.
+ * The respective value of such request key can be obtained by calling
+ * <a href="https://developer.android.com/reference/CaptureRequest/Builder.html#getPhysicalCameraKey">Builder#getPhysicalCameraKey</a>. Capture requests that contain
+ * individual physical device requests must be built via
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureRequest(int,">Set)</a>.</p>
+ *
+ * @see ACAMERA_REQUEST_AVAILABLE_REQUEST_KEYS
+ */
+ ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS = // int32[n]
+ ACAMERA_REQUEST_START + 17,
ACAMERA_REQUEST_END,
/**
@@ -7740,7 +7762,9 @@
typedef enum acamera_metadata_enum_acamera_scaler_available_recommended_stream_configurations {
/**
* <p>Preview must only include non-stalling processed stream configurations with
- * output formats like YUV_420_888, IMPLEMENTATION_DEFINED, etc.</p>
+ * output formats like
+ * {@link AIMAGE_FORMAT_YUV_420_888 },
+ * {@link AIMAGE_FORMAT_PRIVATE }, etc.</p>
*/
ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_PREVIEW
= 0x0,
@@ -7755,19 +7779,20 @@
/**
* <p>Video snapshot must include stream configurations at least as big as
- * the maximum RECORD resolutions and only with format BLOB + DATASPACE_JFIF
- * format/dataspace combination (JPEG). Additionally the configurations shouldn't cause
- * preview glitches and also be able to run at 30 fps.</p>
+ * the maximum RECORD resolutions and only with
+ * {@link AIMAGE_FORMAT_JPEG JPEG output format}.
+ * Additionally the configurations shouldn't cause preview glitches and also be able to
+ * run at 30 fps.</p>
*/
ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_VIDEO_SNAPSHOT
= 0x2,
/**
* <p>Recommended snapshot stream configurations must include at least one with
- * size close to ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE with BLOB + DATASPACE_JFIF
- * format/dataspace combination (JPEG). Taking into account restrictions on aspect
- * ratio, alignment etc. the area of the maximum suggested size shouldn’t be less than
- * 97% of the sensor array size area.</p>
+ * size close to ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE and
+ * {@link AIMAGE_FORMAT_JPEG JPEG output format}.
+ * Taking into account restrictions on aspect ratio, alignment etc. the area of the
+ * maximum suggested size shouldn’t be less than 97% of the sensor array size area.</p>
*
* @see ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE
*/
@@ -7786,9 +7811,20 @@
*/
ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_RAW = 0x5,
- ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_PUBLIC_END
+ /**
+ * <p>If supported, the recommended low latency stream configurations must have
+ * end-to-end latency that does not exceed 200 ms. under standard operating conditions
+ * (reasonable light levels, not loaded system) and using template
+ * TEMPLATE_STILL_CAPTURE. This is primarily for listing configurations for the
+ * {@link AIMAGE_FORMAT_JPEG JPEG output format}
+ * however other supported output formats can be added as well.</p>
+ */
+ ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_LOW_LATENCY_SNAPSHOT
= 0x6,
+ ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_PUBLIC_END
+ = 0x7,
+
/**
* <p>Vendor defined use cases. These depend on the vendor implementation.</p>
*/
diff --git a/camera/ndk/include/camera/NdkCaptureRequest.h b/camera/ndk/include/camera/NdkCaptureRequest.h
index 136989a..d3f8826 100644
--- a/camera/ndk/include/camera/NdkCaptureRequest.h
+++ b/camera/ndk/include/camera/NdkCaptureRequest.h
@@ -358,6 +358,219 @@
#endif /* __ANDROID_API__ >= 28 */
+#if __ANDROID_API__ >= 29
+
+/**
+ * Get a metadata entry from input {@link ACaptureRequest} for
+ * a physical camera backing a logical multi-camera device.
+ *
+ * <p>Same as ACaptureRequest_getConstEntry, except that if the key is contained
+ * in {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}, this function
+ * returns the entry set by ACaptureRequest_setEntry_physicalCamera_* class of
+ * functions on the particular physical camera.</p>
+ *
+ * @param request the {@link ACaptureRequest} of interest created by
+ * {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param physicalId one of the physical Ids used when request is created with
+ * {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param tag the capture request metadata tag in
+ * {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}
+ * that is set by ACaptureRequest_setEntry_physicalCamera_* class of functions.
+ *
+ * @return <ul>
+ * <li>{@link ACAMERA_OK} if the method call succeeds.</li>
+ * <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if metadata, physicalId, or entry is NULL,
+ * physicalId is not one of the Ids used in creating the request, or if the capture
+ * request is a regular request with no physical Ids at all.</li>
+ * <li>{@link ACAMERA_ERROR_METADATA_NOT_FOUND} if the capture request does not contain an
+ * entry of input tag value.</li></ul>
+ */
+camera_status_t ACaptureRequest_getConstEntry_physicalCamera(
+ const ACaptureRequest* request, const char* physicalId, uint32_t tag,
+ ACameraMetadata_const_entry* entry) __INTRODUCED_IN(29);
+
+/**
+ * Set/change a camera capture control entry with unsigned 8 bits data type for
+ * a physical camera backing a logical multi-camera device.
+ *
+ * <p>Same as ACaptureRequest_setEntry_u8, except that if {@link tag} is contained
+ * in {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}, this function
+ * sets the entry for a particular physical sub-camera backing the logical multi-camera.
+ * If {@link tag} is not contained in
+ * {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}, the key will be ignored
+ * by the camera device.</p>
+ *
+ * @param request the {@link ACaptureRequest} of interest created by
+ * {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param physicalId one of the physical Ids used when request is created with
+ * {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param tag one of the capture request metadata tags in
+ * {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}.
+ *
+ * @return <ul>
+ * <li>{@link ACAMERA_OK} if the method call succeeds.</li>
+ * <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if request or physicalId is NULL, count is
+ * larger than zero while data is NULL, the data type of the tag is not unsigned 8 bits,
+ * the tag is not controllable by application, physicalId is not one of the Ids used
+ * in creating the request, or if the capture request is a regular request with no
+ * physical Ids at all.</li></ul>
+ */
+camera_status_t ACaptureRequest_setEntry_physicalCamera_u8(
+ ACaptureRequest* request, const char* physicalId, uint32_t tag,
+ uint32_t count, const uint8_t* data) __INTRODUCED_IN(29);
+
+/**
+ * Set/change a camera capture control entry with signed 32 bits data type for
+ * a physical camera of a logical multi-camera device.
+ *
+ * <p>Same as ACaptureRequest_setEntry_i32, except that if {@link tag} is contained
+ * in {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}, this function
+ * sets the entry for a particular physical sub-camera backing the logical multi-camera.
+ * If {@link tag} is not contained in
+ * {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}, the key will be ignored
+ * by the camera device.</p>
+ *
+ * @param request the {@link ACaptureRequest} of interest created by
+ * {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param physicalId one of the physical Ids used when request is created with
+ * {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param tag one of the capture request metadata tags in
+ * {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}.
+ *
+ * @return <ul>
+ * <li>{@link ACAMERA_OK} if the method call succeeds.</li>
+ * <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if request or physicalId is NULL, count is
+ * larger than zero while data is NULL, the data type of the tag is not signed 32 bits,
+ * the tag is not controllable by application, physicalId is not one of the Ids used
+ * in creating the request, or if the capture request is a regular request with no
+ * physical Ids at all.</li></ul>
+ */
+camera_status_t ACaptureRequest_setEntry_physicalCamera_i32(
+ ACaptureRequest* request, const char* physicalId, uint32_t tag,
+ uint32_t count, const int32_t* data) __INTRODUCED_IN(29);
+
+/**
+ * Set/change a camera capture control entry with float data type for
+ * a physical camera of a logical multi-camera device.
+ *
+ * <p>Same as ACaptureRequest_setEntry_float, except that if {@link tag} is contained
+ * in {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}, this function
+ * sets the entry for a particular physical sub-camera backing the logical multi-camera.
+ * If {@link tag} is not contained in
+ * {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}, the key will be ignored
+ * by the camera device.</p>
+ *
+ * @param request the {@link ACaptureRequest} of interest created by
+ * {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param physicalId one of the physical Ids used when request is created with
+ * {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param tag one of the capture request metadata tags in
+ * {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}.
+ *
+ * @return <ul>
+ * <li>{@link ACAMERA_OK} if the method call succeeds.</li>
+ * <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if request or physicalId is NULL, count is
+ * larger than zero while data is NULL, the data type of the tag is not float,
+ * the tag is not controllable by application, physicalId is not one of the Ids used
+ * in creating the request, or if the capture request is a regular request with no
+ * physical Ids at all.</li></ul>
+ */
+camera_status_t ACaptureRequest_setEntry_physicalCamera_float(
+ ACaptureRequest* request, const char* physicalId, uint32_t tag,
+ uint32_t count, const float* data) __INTRODUCED_IN(29);
+
+/**
+ * Set/change a camera capture control entry with signed 64 bits data type for
+ * a physical camera of a logical multi-camera device.
+ *
+ * <p>Same as ACaptureRequest_setEntry_i64, except that if {@link tag} is contained
+ * in {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}, this function
+ * sets the entry for a particular physical sub-camera backing the logical multi-camera.
+ * If {@link tag} is not contained in
+ * {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}, the key will be ignored
+ * by the camera device.</p>
+ *
+ * @param request the {@link ACaptureRequest} of interest created by
+ * {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param physicalId one of the physical Ids used when request is created with
+ * {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param tag one of the capture request metadata tags in
+ * {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}.
+ *
+ * @return <ul>
+ * <li>{@link ACAMERA_OK} if the method call succeeds.</li>
+ * <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if request or physicalId is NULL, count is
+ * larger than zero while data is NULL, the data type of the tag is not signed 64 bits,
+ * the tag is not controllable by application, physicalId is not one of the Ids used
+ * in creating the request, or if the capture request is a regular request with no
+ * physical Ids at all.</li></ul>
+ */
+camera_status_t ACaptureRequest_setEntry_physicalCamera_i64(
+ ACaptureRequest* request, const char* physicalId, uint32_t tag,
+ uint32_t count, const int64_t* data) __INTRODUCED_IN(29);
+
+/**
+ * Set/change a camera capture control entry with double data type for
+ * a physical camera of a logical multi-camera device.
+ *
+ * <p>Same as ACaptureRequest_setEntry_double, except that if {@link tag} is contained
+ * in {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}, this function
+ * sets the entry for a particular physical sub-camera backing the logical multi-camera.
+ * If {@link tag} is not contained in
+ * {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}, the key will be ignored
+ * by the camera device.</p>
+ *
+ * @param request the {@link ACaptureRequest} of interest created by
+ * {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param physicalId one of the physical Ids used when request is created with
+ * {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param tag one of the capture request metadata tags in
+ * {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}.
+ *
+ * @return <ul>
+ * <li>{@link ACAMERA_OK} if the method call succeeds.</li>
+ * <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if request or physicalId is NULL, count is
+ * larger than zero while data is NULL, the data type of the tag is not double,
+ * the tag is not controllable by application, physicalId is not one of the Ids used
+ * in creating the request, or if the capture request is a regular request with no
+ * physical Ids at all.</li></ul>
+ */
+camera_status_t ACaptureRequest_setEntry_physicalCamera_double(
+ ACaptureRequest* request, const char* physicalId, uint32_t tag,
+ uint32_t count, const double* data) __INTRODUCED_IN(29);
+
+/**
+ * Set/change a camera capture control entry with rational data type for
+ * a physical camera of a logical multi-camera device.
+ *
+ * <p>Same as ACaptureRequest_setEntry_rational, except that if {@link tag} is contained
+ * in {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}, this function
+ * sets the entry for a particular physical sub-camera backing the logical multi-camera.
+ * If {@link tag} is not contained in
+ * {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}, the key will be ignored
+ * by the camera device.</p>
+ *
+ * @param request the {@link ACaptureRequest} of interest created by
+ * {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param physicalId one of the physical Ids used when request is created with
+ * {@link ACameraDevice_createCaptureRequest_withPhysicalIds}.
+ * @param tag one of the capture request metadata tags in
+ * {@link ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS}.
+ *
+ * @return <ul>
+ * <li>{@link ACAMERA_OK} if the method call succeeds.</li>
+ * <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if request or physicalId is NULL, count is
+ * larger than zero while data is NULL, the data type of the tag is not rational,
+ * the tag is not controllable by application, physicalId is not one of the Ids used
+ * in creating the request, or if the capture request is a regular request with no
+ * physical Ids at all.</li></ul>
+ */
+camera_status_t ACaptureRequest_setEntry_physicalCamera_rational(
+ ACaptureRequest* request, const char* physicalId, uint32_t tag,
+ uint32_t count, const ACameraMetadata_rational* data) __INTRODUCED_IN(29);
+
+#endif /* __ANDROID_API__ >= 29 */
+
__END_DECLS
#endif /* _NDK_CAPTURE_REQUEST_H */
diff --git a/camera/ndk/libcamera2ndk.map.txt b/camera/ndk/libcamera2ndk.map.txt
index 5a00022..946a98e 100644
--- a/camera/ndk/libcamera2ndk.map.txt
+++ b/camera/ndk/libcamera2ndk.map.txt
@@ -11,6 +11,7 @@
ACameraCaptureSession_updateSharedOutput; # introduced=28
ACameraDevice_close;
ACameraDevice_createCaptureRequest;
+ ACameraDevice_createCaptureRequest_withPhysicalIds; # introduced=29
ACameraDevice_createCaptureSession;
ACameraDevice_createCaptureSessionWithSessionParameters; # introduced=28
ACameraDevice_getId;
@@ -22,6 +23,8 @@
ACameraManager_openCamera;
ACameraManager_registerAvailabilityCallback;
ACameraManager_unregisterAvailabilityCallback;
+ ACameraManager_registerExtendedAvailabilityCallback; # introduced=29
+ ACameraManager_unregisterExtendedAvailabilityCallback; # introduced=29
ACameraMetadata_copy;
ACameraMetadata_free;
ACameraMetadata_getAllTags;
@@ -34,14 +37,21 @@
ACaptureRequest_free;
ACaptureRequest_getAllTags;
ACaptureRequest_getConstEntry;
+ ACaptureRequest_getConstEntry_physicalCamera; # introduced=29
ACaptureRequest_getUserContext; # introduced=28
ACaptureRequest_removeTarget;
ACaptureRequest_setEntry_double;
+ ACaptureRequest_setEntry_physicalCamera_double; # introduced=29
ACaptureRequest_setEntry_float;
+ ACaptureRequest_setEntry_physicalCamera_float; # introduced=29
ACaptureRequest_setEntry_i32;
+ ACaptureRequest_setEntry_physicalCamera_i32; # introduced=29
ACaptureRequest_setEntry_i64;
+ ACaptureRequest_setEntry_physicalCamera_i64; # introduced=29
ACaptureRequest_setEntry_rational;
+ ACaptureRequest_setEntry_physicalCamera_rational; # introduced=29
ACaptureRequest_setEntry_u8;
+ ACaptureRequest_setEntry_physicalCamera_u8; # introduced=29
ACaptureRequest_setUserContext; # introduced=28
ACaptureSessionOutputContainer_add;
ACaptureSessionOutputContainer_create;
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
index 9aafcd3..a38a31e 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
@@ -138,6 +138,7 @@
camera_status_t
CameraDevice::createCaptureRequest(
ACameraDevice_request_template templateId,
+ const ACameraIdList* physicalCameraIdList,
ACaptureRequest** request) const {
Mutex::Autolock _l(mDeviceLock);
camera_status_t ret = checkCameraClosedOrErrorLocked();
@@ -168,6 +169,12 @@
}
ACaptureRequest* outReq = new ACaptureRequest();
outReq->settings = new ACameraMetadata(rawRequest.release(), ACameraMetadata::ACM_REQUEST);
+ if (physicalCameraIdList != nullptr) {
+ for (auto i = 0; i < physicalCameraIdList->numCameras; i++) {
+ outReq->physicalSettings.emplace(physicalCameraIdList->cameraIds[i],
+ new ACameraMetadata(*(outReq->settings)));
+ }
+ }
outReq->targets = new ACameraOutputTargets();
*request = outReq;
return ACAMERA_OK;
@@ -292,29 +299,16 @@
CameraDevice::allocateCaptureRequestLocked(
const ACaptureRequest* request, /*out*/sp<CaptureRequest> &outReq) {
sp<CaptureRequest> req(new CaptureRequest());
- req->mCaptureRequest.physicalCameraSettings.resize(1);
- req->mCaptureRequest.physicalCameraSettings[0].id = mCameraId;
- // TODO: Do we really need to copy the metadata here ?
- CameraMetadata metadataCopy = request->settings->getInternalData();
- const camera_metadata_t *cameraMetadata = metadataCopy.getAndLock();
- HCameraMetadata hCameraMetadata;
- utils::convertToHidl(cameraMetadata, &hCameraMetadata);
- metadataCopy.unlock(cameraMetadata);
- if (request->settings != nullptr) {
- if (hCameraMetadata.data() != nullptr &&
- mCaptureRequestMetadataQueue != nullptr &&
- mCaptureRequestMetadataQueue->write(
- reinterpret_cast<const uint8_t *>(hCameraMetadata.data()),
- hCameraMetadata.size())) {
- // The metadata field of the union would've been destructued, so no need
- // to re-size it.
- req->mCaptureRequest.physicalCameraSettings[0].settings.fmqMetadataSize(
- hCameraMetadata.size());
- } else {
- ALOGE("Fmq write capture result failed, falling back to hwbinder");
- req->mCaptureRequest.physicalCameraSettings[0].settings.metadata(
- std::move(hCameraMetadata));
- }
+ req->mCaptureRequest.physicalCameraSettings.resize(1 + request->physicalSettings.size());
+
+ size_t index = 0;
+ allocateOneCaptureRequestMetadata(
+ req->mCaptureRequest.physicalCameraSettings[index++], mCameraId, request->settings);
+
+ for (auto& physicalEntry : request->physicalSettings) {
+ allocateOneCaptureRequestMetadata(
+ req->mCaptureRequest.physicalCameraSettings[index++],
+ physicalEntry.first, physicalEntry.second);
}
std::vector<int32_t> requestStreamIdxList;
@@ -356,13 +350,48 @@
return ACAMERA_OK;
}
+void CameraDevice::allocateOneCaptureRequestMetadata(
+ PhysicalCameraSettings& cameraSettings,
+ const std::string& id, const sp<ACameraMetadata>& metadata) {
+ cameraSettings.id = id;
+ // TODO: Do we really need to copy the metadata here ?
+ CameraMetadata metadataCopy = metadata->getInternalData();
+ const camera_metadata_t *cameraMetadata = metadataCopy.getAndLock();
+ HCameraMetadata hCameraMetadata;
+ utils::convertToHidl(cameraMetadata, &hCameraMetadata);
+ metadataCopy.unlock(cameraMetadata);
+ if (metadata != nullptr) {
+ if (hCameraMetadata.data() != nullptr &&
+ mCaptureRequestMetadataQueue != nullptr &&
+ mCaptureRequestMetadataQueue->write(
+ reinterpret_cast<const uint8_t *>(hCameraMetadata.data()),
+ hCameraMetadata.size())) {
+ // The metadata field of the union would've been destructued, so no need
+ // to re-size it.
+ cameraSettings.settings.fmqMetadataSize(hCameraMetadata.size());
+ } else {
+ ALOGE("Fmq write capture result failed, falling back to hwbinder");
+ cameraSettings.settings.metadata(std::move(hCameraMetadata));
+ }
+ }
+}
+
+
ACaptureRequest*
-CameraDevice::allocateACaptureRequest(sp<CaptureRequest>& req) {
+CameraDevice::allocateACaptureRequest(sp<CaptureRequest>& req, const char* deviceId) {
ACaptureRequest* pRequest = new ACaptureRequest();
- CameraMetadata clone;
- utils::convertFromHidlCloned(req->mPhysicalCameraSettings[0].settings.metadata(), &clone);
- pRequest->settings = new ACameraMetadata(clone.release(), ACameraMetadata::ACM_REQUEST);
- pRequest->targets = new ACameraOutputTargets();
+ for (size_t i = 0; i < req->mPhysicalCameraSettings.size(); i++) {
+ const std::string& id = req->mPhysicalCameraSettings[i].id;
+ CameraMetadata clone;
+ utils::convertFromHidlCloned(req->mPhysicalCameraSettings[i].settings.metadata(), &clone);
+ if (id == deviceId) {
+ pRequest->settings = new ACameraMetadata(clone.release(), ACameraMetadata::ACM_REQUEST);
+ } else {
+ pRequest->physicalSettings[req->mPhysicalCameraSettings[i].id] =
+ new ACameraMetadata(clone.release(), ACameraMetadata::ACM_REQUEST);
+ }
+ }
+ pRequest->targets = new ACameraOutputTargets();
for (size_t i = 0; i < req->mSurfaceList.size(); i++) {
native_handle_t* anw = req->mSurfaceList[i];
ACameraOutputTarget outputTarget(anw);
@@ -930,6 +959,7 @@
return;
}
sp<ACameraCaptureSession> session(static_cast<ACameraCaptureSession*>(obj.get()));
+ ACameraDevice* device = session->getDevice();
mCachedSessions.push(session);
sp<CaptureRequest> requestSp = nullptr;
switch (msg->what()) {
@@ -979,7 +1009,7 @@
ALOGE("%s: Cannot find timestamp!", __FUNCTION__);
return;
}
- ACaptureRequest* request = allocateACaptureRequest(requestSp);
+ ACaptureRequest* request = allocateACaptureRequest(requestSp, device->getId());
(*onStart)(context, session.get(), request, timestamp);
freeACaptureRequest(request);
break;
@@ -1002,7 +1032,7 @@
return;
}
sp<ACameraMetadata> result(static_cast<ACameraMetadata*>(obj.get()));
- ACaptureRequest* request = allocateACaptureRequest(requestSp);
+ ACaptureRequest* request = allocateACaptureRequest(requestSp, device->getId());
(*onResult)(context, session.get(), request, result.get());
freeACaptureRequest(request);
break;
@@ -1055,7 +1085,7 @@
physicalMetadataCopyPtrs.push_back(physicalMetadataCopy[i].get());
}
- ACaptureRequest* request = allocateACaptureRequest(requestSp);
+ ACaptureRequest* request = allocateACaptureRequest(requestSp, device->getId());
(*onResult)(context, session.get(), request, result.get(),
physicalResultInfo.size(), physicalCameraIdPtrs.data(),
physicalMetadataCopyPtrs.data());
@@ -1084,7 +1114,7 @@
static_cast<CameraCaptureFailure*>(obj.get()));
ACameraCaptureFailure* failure =
static_cast<ACameraCaptureFailure*>(failureSp.get());
- ACaptureRequest* request = allocateACaptureRequest(requestSp);
+ ACaptureRequest* request = allocateACaptureRequest(requestSp, device->getId());
(*onFail)(context, session.get(), request, failure);
freeACaptureRequest(request);
break;
@@ -1161,7 +1191,7 @@
return;
}
- ACaptureRequest* request = allocateACaptureRequest(requestSp);
+ ACaptureRequest* request = allocateACaptureRequest(requestSp, device->getId());
(*onBufferLost)(context, session.get(), request, anw, frameNumber);
freeACaptureRequest(request);
break;
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.h b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
index d571585..28092fd 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDevice.h
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
@@ -92,6 +92,7 @@
camera_status_t createCaptureRequest(
ACameraDevice_request_template templateId,
+ const ACameraIdList* physicalCameraIdList,
ACaptureRequest** request) const;
camera_status_t createCaptureSession(
@@ -176,8 +177,11 @@
// metadata associated with it.
camera_status_t allocateCaptureRequestLocked(
const ACaptureRequest* request, sp<CaptureRequest>& outReq);
+ void allocateOneCaptureRequestMetadata(
+ PhysicalCameraSettings& cameraSettings,
+ const std::string& id, const sp<ACameraMetadata>& metadata);
- static ACaptureRequest* allocateACaptureRequest(sp<CaptureRequest>& req);
+ static ACaptureRequest* allocateACaptureRequest(sp<CaptureRequest>& req, const char* deviceId);
static void freeACaptureRequest(ACaptureRequest*);
// only For session to hold device lock
@@ -380,8 +384,9 @@
camera_status_t createCaptureRequest(
ACameraDevice_request_template templateId,
+ const ACameraIdList* physicalCameraIdList,
ACaptureRequest** request) const {
- return mDevice->createCaptureRequest(templateId, request);
+ return mDevice->createCaptureRequest(templateId, physicalCameraIdList, request);
}
camera_status_t createCaptureSession(
diff --git a/camera/ndk/ndk_vendor/impl/ACameraManager.h b/camera/ndk/ndk_vendor/impl/ACameraManager.h
index 6b1365a..df69353 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraManager.h
+++ b/camera/ndk/ndk_vendor/impl/ACameraManager.h
@@ -64,6 +64,11 @@
void unregisterAvailabilityCallback(
const ACameraManager_AvailabilityCallbacks *callback);
+ void registerExtendedAvailabilityCallback(
+ const ACameraManager_ExtendedAvailabilityCallbacks* /*callback*/) {}
+ void unregisterExtendedAvailabilityCallback(
+ const ACameraManager_ExtendedAvailabilityCallbacks* /*callback*/) {}
+
/**
* Return camera IDs that support camera2
*/
diff --git a/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp b/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
index 93108b0..2398922 100644
--- a/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
+++ b/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
@@ -61,7 +61,8 @@
native_handle_t* anw;
};
int initCamera(native_handle_t* imgReaderAnw,
- const std::vector<PhysicalImgReaderInfo>& physicalImgReaders) {
+ const std::vector<PhysicalImgReaderInfo>& physicalImgReaders,
+ bool usePhysicalSettings) {
if (imgReaderAnw == nullptr) {
ALOGE("Cannot initialize camera before image reader get initialized.");
return -1;
@@ -97,6 +98,7 @@
return ret;
}
+ std::vector<const char*> idPointerList;
for (auto& physicalStream : physicalImgReaders) {
ACaptureSessionOutput* sessionOutput = nullptr;
ret = ACaptureSessionPhysicalOutput_create(physicalStream.anw,
@@ -113,7 +115,11 @@
mExtraOutputs.push_back(sessionOutput);
// Assume that at most one physical stream per physical camera.
mPhysicalCameraIds.push_back(physicalStream.physicalCameraId);
+ idPointerList.push_back(physicalStream.physicalCameraId);
}
+ ACameraIdList cameraIdList;
+ cameraIdList.numCameras = idPointerList.size();
+ cameraIdList.cameraIds = idPointerList.data();
ret = ACameraDevice_createCaptureSession(mDevice, mOutputs, &mSessionCb, &mSession);
if (ret != AMEDIA_OK) {
@@ -122,7 +128,13 @@
}
// Create capture request
- ret = ACameraDevice_createCaptureRequest(mDevice, TEMPLATE_STILL_CAPTURE, &mStillRequest);
+ if (usePhysicalSettings) {
+ ret = ACameraDevice_createCaptureRequest_withPhysicalIds(mDevice,
+ TEMPLATE_STILL_CAPTURE, &cameraIdList, &mStillRequest);
+ } else {
+ ret = ACameraDevice_createCaptureRequest(mDevice,
+ TEMPLATE_STILL_CAPTURE, &mStillRequest);
+ }
if (ret != AMEDIA_OK) {
ALOGE("ACameraDevice_createCaptureRequest failed, ret=%d", ret);
return ret;
@@ -557,7 +569,8 @@
}
CameraHelper cameraHelper(id, mCameraManager);
- ret = cameraHelper.initCamera(testCase.getNativeWindow(), {});
+ ret = cameraHelper.initCamera(testCase.getNativeWindow(),
+ {}/*physicalImageReaders*/, false/*usePhysicalSettings*/);
if (ret < 0) {
ALOGE("Unable to initialize camera helper");
return false;
@@ -695,6 +708,69 @@
*cameraId = nullptr;
return;
}
+
+ void testLogicalCameraPhysicalStream(bool usePhysicalSettings) {
+ const char* cameraId = nullptr;
+ ACameraMetadata* staticMetadata = nullptr;
+ std::vector<const char*> physicalCameraIds;
+
+ findCandidateLogicalCamera(&cameraId, &staticMetadata, &physicalCameraIds);
+ if (cameraId == nullptr) {
+ // Couldn't find logical camera to test
+ return;
+ }
+
+ // Test streaming the logical multi-camera
+ uint64_t readerUsage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN;
+ int32_t readerMaxImages = 8;
+ bool readerAsync = false;
+ const int pictureCount = 6;
+ std::vector<ImageReaderTestCase*> testCases;
+ for (size_t i = 0; i < 3; i++) {
+ ImageReaderTestCase* testCase = new ImageReaderTestCase(
+ kTestImageWidth, kTestImageHeight, kTestImageFormat, readerUsage,
+ readerMaxImages, readerAsync);
+ ASSERT_EQ(testCase->initImageReader(), 0);
+ testCases.push_back(testCase);
+ }
+
+ CameraHelper cameraHelper(cameraId, mCameraManager);
+ std::vector<CameraHelper::PhysicalImgReaderInfo> physicalImgReaderInfo;
+ physicalImgReaderInfo.push_back({physicalCameraIds[0], testCases[1]->getNativeWindow()});
+ physicalImgReaderInfo.push_back({physicalCameraIds[1], testCases[2]->getNativeWindow()});
+
+ int ret = cameraHelper.initCamera(testCases[0]->getNativeWindow(),
+ physicalImgReaderInfo, usePhysicalSettings);
+ ASSERT_EQ(ret, 0);
+
+ if (!cameraHelper.isCameraReady()) {
+ ALOGW("Camera is not ready after successful initialization. It's either due to camera "
+ "on board lacks BACKWARDS_COMPATIBLE capability or the device does not have "
+ "camera on board.");
+ return;
+ }
+
+ for (int i = 0; i < pictureCount; i++) {
+ ret = cameraHelper.takeLogicalCameraPicture();
+ ASSERT_EQ(ret, 0);
+ }
+
+ // Sleep until all capture finished
+ for (int i = 0; i < kCaptureWaitRetry * pictureCount; i++) {
+ usleep(kCaptureWaitUs);
+ if (testCases[0]->getAcquiredImageCount() == pictureCount) {
+ ALOGI("Session take ~%d ms to capture %d images", i * kCaptureWaitUs / 1000,
+ pictureCount);
+ break;
+ }
+ }
+ ASSERT_EQ(testCases[0]->getAcquiredImageCount(), pictureCount);
+ ASSERT_EQ(testCases[1]->getAcquiredImageCount(), pictureCount);
+ ASSERT_EQ(testCases[2]->getAcquiredImageCount(), pictureCount);
+ ASSERT_TRUE(cameraHelper.checkCallbacks(pictureCount));
+
+ ACameraMetadata_free(staticMetadata);
+ }
};
TEST_F(AImageReaderVendorTest, CreateWindowNativeHandle) {
@@ -722,65 +798,8 @@
}
TEST_F(AImageReaderVendorTest, LogicalCameraPhysicalStream) {
- const char* cameraId = nullptr;
- ACameraMetadata* staticMetadata = nullptr;
- std::vector<const char*> physicalCameraIds;
-
- findCandidateLogicalCamera(&cameraId, &staticMetadata, &physicalCameraIds);
- if (cameraId == nullptr) {
- // Couldn't find logical camera to test
- return;
- }
-
- // Test streaming the logical multi-camera
- uint64_t readerUsage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN;
- int32_t readerMaxImages = 8;
- bool readerAsync = false;
- const int pictureCount = 6;
- std::vector<ImageReaderTestCase*> testCases;
- for (size_t i = 0; i < 3; i++) {
- ImageReaderTestCase* testCase = new ImageReaderTestCase(
- kTestImageWidth, kTestImageHeight, kTestImageFormat, readerUsage, readerMaxImages,
- readerAsync);
- ASSERT_EQ(testCase->initImageReader(), 0);
- testCases.push_back(testCase);
- }
-
- CameraHelper cameraHelper(cameraId, mCameraManager);
- std::vector<CameraHelper::PhysicalImgReaderInfo> physicalImgReaderInfo;
- physicalImgReaderInfo.push_back({physicalCameraIds[0], testCases[1]->getNativeWindow()});
- physicalImgReaderInfo.push_back({physicalCameraIds[1], testCases[2]->getNativeWindow()});
-
- int ret = cameraHelper.initCamera(testCases[0]->getNativeWindow(), physicalImgReaderInfo);
- ASSERT_EQ(ret, 0);
-
- if (!cameraHelper.isCameraReady()) {
- ALOGW("Camera is not ready after successful initialization. It's either due to camera on "
- "board lacks BACKWARDS_COMPATIBLE capability or the device does not have camera on "
- "board.");
- return;
- }
-
- for (int i = 0; i < pictureCount; i++) {
- ret = cameraHelper.takeLogicalCameraPicture();
- ASSERT_EQ(ret, 0);
- }
-
- // Sleep until all capture finished
- for (int i = 0; i < kCaptureWaitRetry * pictureCount; i++) {
- usleep(kCaptureWaitUs);
- if (testCases[0]->getAcquiredImageCount() == pictureCount) {
- ALOGI("Session take ~%d ms to capture %d images", i * kCaptureWaitUs / 1000,
- pictureCount);
- break;
- }
- }
- ASSERT_EQ(testCases[0]->getAcquiredImageCount(), pictureCount);
- ASSERT_EQ(testCases[1]->getAcquiredImageCount(), pictureCount);
- ASSERT_EQ(testCases[2]->getAcquiredImageCount(), pictureCount);
- ASSERT_TRUE(cameraHelper.checkCallbacks(pictureCount));
-
- ACameraMetadata_free(staticMetadata);
+ testLogicalCameraPhysicalStream(false/*usePhysicalSettings*/);
+ testLogicalCameraPhysicalStream(true/*usePhysicalSettings*/);
}
} // namespace
diff --git a/drm/mediadrm/plugins/clearkey/hidl/CryptoPlugin.cpp b/drm/mediadrm/plugins/clearkey/hidl/CryptoPlugin.cpp
index fc0cceb..23a35e5 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/CryptoPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/CryptoPlugin.cpp
@@ -135,7 +135,7 @@
}
if (destBuffer.offset + destBuffer.size > destBase->getSize()) {
- _hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0, "invalid buffer size");
+ _hidl_cb(Status_V1_2::ERROR_DRM_FRAME_TOO_LARGE, 0, "invalid buffer size");
return Void();
}
destPtr = static_cast<void *>(base + destination.nonsecureMemory.offset);
diff --git a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
index badb99e..d7dacb8 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
@@ -527,6 +527,10 @@
mMockError = Status_V1_2::ERROR_DRM_SESSION_LOST_STATE;
} else if (value == kFrameTooLargeValue) {
mMockError = Status_V1_2::ERROR_DRM_FRAME_TOO_LARGE;
+ } else if (value == kInvalidStateValue) {
+ mMockError = Status_V1_2::ERROR_DRM_INVALID_STATE;
+ } else {
+ mMockError = Status_V1_2::ERROR_DRM_UNKNOWN;
}
}
@@ -683,6 +687,10 @@
Return<void> DrmPlugin::getOfflineLicenseKeySetIds(getOfflineLicenseKeySetIds_cb _hidl_cb) {
std::vector<std::string> licenseNames = mFileHandle.ListLicenses();
std::vector<KeySetId> keySetIds;
+ if (mMockError != Status_V1_2::OK) {
+ _hidl_cb(toStatus_1_0(mMockError), keySetIds);
+ return Void();
+ }
for (const auto& name : licenseNames) {
std::vector<uint8_t> keySetId(name.begin(), name.end());
keySetIds.push_back(keySetId);
@@ -693,6 +701,9 @@
Return<Status> DrmPlugin::removeOfflineLicense(const KeySetId& keySetId) {
+ if (mMockError != Status_V1_2::OK) {
+ return toStatus_1_0(mMockError);
+ }
std::string licenseName(keySetId.begin(), keySetId.end());
if (mFileHandle.DeleteLicense(licenseName)) {
return Status::OK;
@@ -706,7 +717,9 @@
DeviceFiles::LicenseState state;
std::string license;
OfflineLicenseState hLicenseState;
- if (mFileHandle.RetrieveLicense(licenseName, &state, &license)) {
+ if (mMockError != Status_V1_2::OK) {
+ _hidl_cb(toStatus_1_0(mMockError), OfflineLicenseState::UNKNOWN);
+ } else if (mFileHandle.RetrieveLicense(licenseName, &state, &license)) {
switch (state) {
case DeviceFiles::kLicenseStateActive:
hLicenseState = OfflineLicenseState::USABLE;
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyDrmProperties.h b/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyDrmProperties.h
index 1bbc822..b83ce69 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyDrmProperties.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyDrmProperties.h
@@ -40,6 +40,7 @@
static const std::string kResourceContentionValue("resourceContention");
static const std::string kLostStateValue("lostState");
static const std::string kFrameTooLargeValue("frameTooLarge");
+static const std::string kInvalidStateValue("invalidState");
static const std::string kDeviceIdKey("deviceId");
static const uint8_t kTestDeviceIdData[] =
diff --git a/media/codec2/components/hevc/C2SoftHevcEnc.cpp b/media/codec2/components/hevc/C2SoftHevcEnc.cpp
index 2c0a7a0..7045b6a 100644
--- a/media/codec2/components/hevc/C2SoftHevcEnc.cpp
+++ b/media/codec2/components/hevc/C2SoftHevcEnc.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2019 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.
@@ -39,7 +39,7 @@
namespace android {
class C2SoftHevcEnc::IntfImpl : public C2InterfaceHelper {
- public:
+ public:
explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper>& helper)
: C2InterfaceHelper(helper) {
setDerivedInstance(this);
@@ -73,6 +73,7 @@
0u, (uint64_t)C2MemoryUsage::CPU_READ))
.build());
+ // matches size limits in codec library
addParameter(
DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE)
.withDefault(new C2StreamPictureSizeInfo::input(0u, 320, 240))
@@ -91,6 +92,7 @@
Setter<decltype(*mFrameRate)>::StrictValueWithNoDeps)
.build());
+ // matches limits in codec library
addParameter(
DefineParam(mBitrate, C2_PARAMKEY_BITRATE)
.withDefault(new C2StreamBitrateInfo::output(0u, 64000))
@@ -98,6 +100,7 @@
.withSetter(BitrateSetter)
.build());
+ // matches levels allowed within codec library
addParameter(
DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
.withDefault(new C2StreamProfileLevelInfo::output(
@@ -137,7 +140,7 @@
C2P<C2StreamBitrateInfo::output>& me) {
(void)mayBlock;
C2R res = C2R::Ok();
- if (me.v.value <= 4096) {
+ if (me.v.value < 4096) {
me.set().value = 4096;
}
return res;
@@ -278,7 +281,7 @@
return (uint32_t)c2_max(c2_min(period + 0.5, double(UINT32_MAX)), 1.);
}
- std::shared_ptr<C2StreamPictureSizeInfo::input> getSize_l() const {
+ std::shared_ptr<C2StreamPictureSizeInfo::input> getSize_l() const {
return mSize;
}
std::shared_ptr<C2StreamFrameRateInfo::output> getFrameRate_l() const {
@@ -304,18 +307,21 @@
std::shared_ptr<C2StreamProfileLevelInfo::output> mProfileLevel;
std::shared_ptr<C2StreamSyncFrameIntervalTuning::output> mSyncFramePeriod;
};
+
constexpr char COMPONENT_NAME[] = "c2.android.hevc.encoder";
static size_t GetCPUCoreCount() {
- long cpuCoreCount = 1;
+ long cpuCoreCount = 0;
+
#if defined(_SC_NPROCESSORS_ONLN)
cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
#else
// _SC_NPROC_ONLN must be defined...
cpuCoreCount = sysconf(_SC_NPROC_ONLN);
#endif
- CHECK(cpuCoreCount >= 1);
- ALOGV("Number of CPU cores: %ld", cpuCoreCount);
+
+ if (cpuCoreCount < 1)
+ cpuCoreCount = 1;
return (size_t)cpuCoreCount;
}
@@ -383,7 +389,7 @@
c2_status_t C2SoftHevcEnc::initEncParams() {
mCodecCtx = nullptr;
- mNumCores = MIN(GetCPUCoreCount(), CODEC_MAX_CORES);
+ mNumCores = std::min(GetCPUCoreCount(), (size_t) CODEC_MAX_CORES);
memset(&mEncParams, 0, sizeof(ihevce_static_cfg_params_t));
// default configuration
@@ -397,7 +403,8 @@
mEncParams.s_src_prms.i4_width = mSize->width;
mEncParams.s_src_prms.i4_height = mSize->height;
mEncParams.s_src_prms.i4_frm_rate_denom = 1000;
- mEncParams.s_src_prms.i4_frm_rate_num = mFrameRate->value * mEncParams.s_src_prms.i4_frm_rate_denom;
+ mEncParams.s_src_prms.i4_frm_rate_num =
+ mFrameRate->value * mEncParams.s_src_prms.i4_frm_rate_denom;
mEncParams.s_tgt_lyr_prms.as_tgt_params[0].i4_quality_preset = IHEVCE_QUALITY_P5;
mEncParams.s_tgt_lyr_prms.as_tgt_params[0].ai4_tgt_bitrate[0] =
mBitrate->value;
@@ -470,7 +477,7 @@
const C2GraphicView* const input,
uint64_t timestamp) {
ihevce_static_cfg_params_t* params = &mEncParams;
- memset(ps_encode_ip, 0, sizeof(ihevce_inp_buf_t));
+ memset(ps_encode_ip, 0, sizeof(*ps_encode_ip));
if (!input) {
return C2_OK;
@@ -495,13 +502,14 @@
int32_t uStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc;
int32_t vStride = layout.planes[C2PlanarLayout::PLANE_V].rowInc;
- uint32_t width = mSize->width;
- uint32_t height = mSize->height;
+ const uint32_t width = mSize->width;
+ const uint32_t height = mSize->height;
- // width and height are always even
- // width and height are always even (as block size is 16x16)
- CHECK_EQ((width & 1u), 0u);
- CHECK_EQ((height & 1u), 0u);
+ // width and height must be even
+ if (width & 1u || height & 1u) {
+ ALOGW("height(%u) and width(%u) must both be even", height, width);
+ return C2_BAD_VALUE;
+ }
size_t yPlaneSize = width * height;
@@ -650,6 +658,7 @@
if (view->error() != C2_OK) {
ALOGE("graphic view map err = %d", view->error());
mSignalledError = true;
+ work->result = C2_CORRUPTED;
return;
}
}
@@ -687,8 +696,8 @@
status = setEncodeArgs(&s_encode_ip, view.get(), timestamp);
if (C2_OK != status) {
- mSignalledError = true;
ALOGE("setEncodeArgs failed : 0x%x", status);
+ mSignalledError = true;
work->result = status;
return;
}
@@ -761,8 +770,9 @@
: mHelper(std::static_pointer_cast<C2ReflectorHelper>(
GetCodec2PlatformComponentStore()->getParamReflector())) {}
- virtual c2_status_t createComponent(
- c2_node_id_t id, std::shared_ptr<C2Component>* const component,
+ c2_status_t createComponent(
+ c2_node_id_t id,
+ std::shared_ptr<C2Component>* const component,
std::function<void(C2Component*)> deleter) override {
*component = std::shared_ptr<C2Component>(
new C2SoftHevcEnc(
@@ -772,8 +782,9 @@
return C2_OK;
}
- virtual c2_status_t createInterface(
- c2_node_id_t id, std::shared_ptr<C2ComponentInterface>* const interface,
+ c2_status_t createInterface(
+ c2_node_id_t id,
+ std::shared_ptr<C2ComponentInterface>* const interface,
std::function<void(C2ComponentInterface*)> deleter) override {
*interface = std::shared_ptr<C2ComponentInterface>(
new SimpleInterface<C2SoftHevcEnc::IntfImpl>(
@@ -783,7 +794,7 @@
return C2_OK;
}
- virtual ~C2SoftHevcEncFactory() override = default;
+ ~C2SoftHevcEncFactory() override = default;
private:
std::shared_ptr<C2ReflectorHelper> mHelper;
diff --git a/media/codec2/components/hevc/C2SoftHevcEnc.h b/media/codec2/components/hevc/C2SoftHevcEnc.h
index c22fea2..9d90b95 100644
--- a/media/codec2/components/hevc/C2SoftHevcEnc.h
+++ b/media/codec2/components/hevc/C2SoftHevcEnc.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 The Android Open Source Project
+ * Copyright 2019 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.
@@ -17,18 +17,18 @@
#ifndef ANDROID_C2_SOFT_HEVC_ENC_H_
#define ANDROID_C2_SOFT_HEVC_ENC_H_
-#include <map>
-#include <utils/Vector.h>
-#include <media/stagefright/foundation/ColorUtils.h>
#include <SimpleC2Component.h>
+#include <algorithm>
+#include <map>
+#include <media/stagefright/foundation/ColorUtils.h>
+#include <utils/Vector.h>
#include "ihevc_typedefs.h"
namespace android {
-#define MIN(a, b) ((a) < (b)) ? (a) : (b)
/** Get time */
-#define GETTIME(a, b) gettimeofday(a, b);
+#define GETTIME(a, b) gettimeofday(a, b)
/** Compute difference between start and end */
#define TIME_DIFF(start, end, diff) \
@@ -55,7 +55,7 @@
const std::shared_ptr<C2BlockPool>& pool) override;
protected:
- virtual ~C2SoftHevcEnc();
+ ~C2SoftHevcEnc() override;
private:
std::shared_ptr<IntfImpl> mIntf;
diff --git a/media/codec2/components/opus/C2SoftOpusDec.cpp b/media/codec2/components/opus/C2SoftOpusDec.cpp
index 680712e..7dcd53d 100644
--- a/media/codec2/components/opus/C2SoftOpusDec.cpp
+++ b/media/codec2/components/opus/C2SoftOpusDec.cpp
@@ -252,20 +252,25 @@
const uint8_t *data = rView.data() + inOffset;
if (mInputBufferCount < 3) {
if (mInputBufferCount == 0) {
- size_t opusHeadSize = inSize;
+ size_t opusHeadSize = 0;
size_t codecDelayBufSize = 0;
size_t seekPreRollBufSize = 0;
- void *opusHeadBuf = (void *)data;
+ void *opusHeadBuf = NULL;
void *codecDelayBuf = NULL;
void *seekPreRollBuf = NULL;
- GetOpusHeaderBuffers(data, inSize, &opusHeadBuf,
- &opusHeadSize, &codecDelayBuf,
- &codecDelayBufSize, &seekPreRollBuf,
- &seekPreRollBufSize);
+ if (!GetOpusHeaderBuffers(data, inSize, &opusHeadBuf,
+ &opusHeadSize, &codecDelayBuf,
+ &codecDelayBufSize, &seekPreRollBuf,
+ &seekPreRollBufSize)) {
+ ALOGE("%s encountered error in GetOpusHeaderBuffers", __func__);
+ mSignalledError = true;
+ work->result = C2_CORRUPTED;
+ return;
+ }
if (!ParseOpusHeader((uint8_t *)opusHeadBuf, opusHeadSize, &mHeader)) {
- ALOGE("Encountered error while Parsing Opus Header.");
+ ALOGE("%s Encountered error while Parsing Opus Header.", __func__);
mSignalledError = true;
work->result = C2_CORRUPTED;
return;
@@ -304,16 +309,16 @@
return;
}
- if (codecDelayBuf && codecDelayBufSize == 8) {
+ if (codecDelayBuf && codecDelayBufSize == sizeof(uint64_t)) {
uint64_t value;
memcpy(&value, codecDelayBuf, sizeof(uint64_t));
mCodecDelay = ns_to_samples(value, kRate);
mSamplesToDiscard = mCodecDelay;
++mInputBufferCount;
}
- if (seekPreRollBuf && seekPreRollBufSize == 8) {
+ if (seekPreRollBuf && seekPreRollBufSize == sizeof(uint64_t)) {
uint64_t value;
- memcpy(&value, codecDelayBuf, sizeof(uint64_t));
+ memcpy(&value, seekPreRollBuf, sizeof(uint64_t));
mSeekPreRoll = ns_to_samples(value, kRate);
++mInputBufferCount;
}
diff --git a/media/codec2/hidl/1.0/vts/functional/audio/VtsHidlC2V1_0TargetAudioDecTest.cpp b/media/codec2/hidl/1.0/vts/functional/audio/VtsHidlC2V1_0TargetAudioDecTest.cpp
index d3b37d7..89947d4 100644
--- a/media/codec2/hidl/1.0/vts/functional/audio/VtsHidlC2V1_0TargetAudioDecTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/audio/VtsHidlC2V1_0TargetAudioDecTest.cpp
@@ -506,16 +506,17 @@
ASSERT_EQ(mComponent->stop(), C2_OK);
}
-class Codec2AudioDecDecodeTest : public Codec2AudioDecHidlTest,
- public ::testing::WithParamInterface<int32_t> {
+class Codec2AudioDecDecodeTest
+ : public Codec2AudioDecHidlTest,
+ public ::testing::WithParamInterface<std::pair<int32_t, bool>> {
};
TEST_P(Codec2AudioDecDecodeTest, DecodeTest) {
description("Decodes input file");
if (mDisableTest) return;
- uint32_t streamIndex = GetParam();
- ASSERT_EQ(mComponent->start(), C2_OK);
+ uint32_t streamIndex = GetParam().first;
+ bool signalEOS = GetParam().second;
mTimestampDevTest = true;
char mURL[512], info[512];
std::ifstream eleStream, eleInfo;
@@ -567,16 +568,27 @@
ASSERT_EQ(eleStream.is_open(), true);
ASSERT_NO_FATAL_FAILURE(decodeNFrames(
mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices,
- mLinearPool, eleStream, &Info, 0, (int)Info.size()));
+ mLinearPool, eleStream, &Info, 0, (int)Info.size(), signalEOS));
+
+ // If EOS is not sent, sending empty input with EOS flag
+ size_t infoSize = Info.size();
+ if (!signalEOS) {
+ ASSERT_NO_FATAL_FAILURE(
+ waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue, 1));
+ ASSERT_NO_FATAL_FAILURE(
+ testInputBuffer(mComponent, mQueueLock, mWorkQueue,
+ C2FrameData::FLAG_END_OF_STREAM, false));
+ infoSize += 1;
+ }
// blocking call to ensures application to Wait till all the inputs are
// consumed
ASSERT_NO_FATAL_FAILURE(
waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
eleStream.close();
- if (mFramesReceived != Info.size()) {
+ if (mFramesReceived != infoSize) {
ALOGE("Input buffer count and Output buffer count mismatch");
ALOGE("framesReceived : %d inputFrames : %zu", mFramesReceived,
- Info.size());
+ infoSize);
ASSERT_TRUE(false);
}
ASSERT_EQ(mEos, true);
@@ -608,9 +620,12 @@
}
ASSERT_EQ(mComponent->stop(), C2_OK);
}
-
-INSTANTIATE_TEST_CASE_P(StreamIndexes, Codec2AudioDecDecodeTest,
- ::testing::Values(0, 1));
+// DecodeTest with StreamIndex and EOS / No EOS
+INSTANTIATE_TEST_CASE_P(StreamIndexAndEOS, Codec2AudioDecDecodeTest,
+ ::testing::Values(std::make_pair(0, false),
+ std::make_pair(0, true),
+ std::make_pair(1, false),
+ std::make_pair(1, true)));
// thumbnail test
TEST_F(Codec2AudioDecHidlTest, ThumbnailTest) {
diff --git a/media/codec2/hidl/1.0/vts/functional/audio/VtsHidlC2V1_0TargetAudioEncTest.cpp b/media/codec2/hidl/1.0/vts/functional/audio/VtsHidlC2V1_0TargetAudioEncTest.cpp
index a74d43e..0946fa6 100644
--- a/media/codec2/hidl/1.0/vts/functional/audio/VtsHidlC2V1_0TargetAudioEncTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/audio/VtsHidlC2V1_0TargetAudioEncTest.cpp
@@ -123,6 +123,7 @@
mFramesReceived = 0;
if (mCompName == unknown_comp) mDisableTest = true;
if (mDisableTest) std::cout << "[ WARN ] Test Disabled \n";
+ getInputMaxBufSize();
}
virtual void TearDown() override {
@@ -157,6 +158,7 @@
bool mDisableTest;
standardComp mCompName;
uint32_t mFramesReceived;
+ int32_t mInputMaxBufSize;
std::list<uint64_t> mFlushedIndices;
C2BlockPool::local_id_t mBlockPoolId;
@@ -175,6 +177,27 @@
static void description(const std::string& description) {
RecordProperty("description", description);
}
+
+ // In encoder components, fetch the size of input buffer allocated
+ void getInputMaxBufSize() {
+ int32_t bitStreamInfo[1] = {0};
+ std::vector<std::unique_ptr<C2Param>> inParams;
+ c2_status_t status = mComponent->query(
+ {}, {C2StreamMaxBufferSizeInfo::input::PARAM_TYPE}, C2_DONT_BLOCK,
+ &inParams);
+ if (status != C2_OK && inParams.size() == 0) {
+ ALOGE("Query MaxBufferSizeInfo failed => %d", status);
+ ASSERT_TRUE(false);
+ } else {
+ size_t offset = sizeof(C2Param);
+ for (size_t i = 0; i < inParams.size(); ++i) {
+ C2Param* param = inParams[i].get();
+ bitStreamInfo[i] = *(int32_t*)((uint8_t*)param + offset);
+ }
+ }
+ mInputMaxBufSize = bitStreamInfo[0];
+ }
+
};
void validateComponent(
@@ -355,60 +378,79 @@
ASSERT_EQ(mDisableTest, false);
}
-TEST_F(Codec2AudioEncHidlTest, EncodeTest) {
+class Codec2AudioEncEncodeTest
+ : public Codec2AudioEncHidlTest,
+ public ::testing::WithParamInterface<std::pair<bool, int32_t>> {
+};
+
+TEST_P(Codec2AudioEncEncodeTest, EncodeTest) {
ALOGV("EncodeTest");
if (mDisableTest) return;
char mURL[512];
strcpy(mURL, gEnv->getRes().c_str());
GetURLForComponent(mCompName, mURL);
+ bool signalEOS = GetParam().first;
+ // Ratio w.r.t to mInputMaxBufSize
+ int32_t inputMaxBufRatio = GetParam().second;
- // Setting default configuration
+ // Setting default sampleRate
int32_t nChannels = 2;
int32_t nSampleRate = 44100;
- int32_t samplesPerFrame = 1024;
switch (mCompName) {
case aac:
nChannels = 2;
nSampleRate = 48000;
- samplesPerFrame = 1024;
break;
case flac:
nChannels = 2;
nSampleRate = 48000;
- samplesPerFrame = 1152;
break;
case opus:
nChannels = 2;
nSampleRate = 48000;
- samplesPerFrame = 960;
break;
case amrnb:
nChannels = 1;
nSampleRate = 8000;
- samplesPerFrame = 160;
break;
case amrwb:
nChannels = 1;
nSampleRate = 16000;
- samplesPerFrame = 160;
break;
default:
ASSERT_TRUE(false);
}
+ int32_t samplesPerFrame =
+ ((mInputMaxBufSize / inputMaxBufRatio) / (nChannels * 2));
+ ALOGV("signalEOS %d mInputMaxBufSize %d samplesPerFrame %d", signalEOS,
+ mInputMaxBufSize, samplesPerFrame);
+
if (!setupConfigParam(mComponent, nChannels, nSampleRate)) {
std::cout << "[ WARN ] Test Skipped \n";
return;
}
ASSERT_EQ(mComponent->start(), C2_OK);
std::ifstream eleStream;
- uint32_t numFrames = 128;
+ uint32_t numFrames = 16;
eleStream.open(mURL, std::ifstream::binary);
ASSERT_EQ(eleStream.is_open(), true);
ALOGV("mURL : %s", mURL);
ASSERT_NO_FATAL_FAILURE(
encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
mFlushedIndices, mLinearPool, eleStream, numFrames,
- samplesPerFrame, nChannels, nSampleRate));
+ samplesPerFrame, nChannels, nSampleRate, false,
+ signalEOS));
+
+ // If EOS is not sent, sending empty input with EOS flag
+ if (!signalEOS) {
+ ASSERT_NO_FATAL_FAILURE(
+ waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue, 1));
+ ASSERT_NO_FATAL_FAILURE(
+ testInputBuffer(mComponent, mQueueLock, mWorkQueue,
+ C2FrameData::FLAG_END_OF_STREAM, false));
+ numFrames += 1;
+ }
+
// blocking call to ensures application to Wait till all the inputs are
// consumed
ASSERT_NO_FATAL_FAILURE(
@@ -429,6 +471,15 @@
ASSERT_EQ(mComponent->stop(), C2_OK);
}
+// EncodeTest with EOS / No EOS and inputMaxBufRatio
+// inputMaxBufRatio is ratio w.r.t. to mInputMaxBufSize
+INSTANTIATE_TEST_CASE_P(EncodeTest, Codec2AudioEncEncodeTest,
+ ::testing::Values(std::make_pair(false, 1),
+ std::make_pair(false, 2),
+ std::make_pair(true, 1),
+ std::make_pair(true, 2)));
+
+
TEST_F(Codec2AudioEncHidlTest, EOSTest) {
description("Test empty input buffer with EOS flag");
if (mDisableTest) return;
diff --git a/media/codec2/hidl/1.0/vts/functional/master/VtsHidlC2V1_0TargetMasterTest.cpp b/media/codec2/hidl/1.0/vts/functional/master/VtsHidlC2V1_0TargetMasterTest.cpp
index 01e64cb..e88fbc7 100644
--- a/media/codec2/hidl/1.0/vts/functional/master/VtsHidlC2V1_0TargetMasterTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/master/VtsHidlC2V1_0TargetMasterTest.cpp
@@ -64,7 +64,7 @@
C2String name = mClient->getName();
EXPECT_NE(name.empty(), true) << "Invalid Codec2Client Name";
- // Get List of components from HIDL Codec2Client instance
+ // Get List of components from all known services
const std::vector<C2Component::Traits> listTraits =
mClient->ListComponents();
@@ -78,8 +78,9 @@
listener.reset(new CodecListener());
ASSERT_NE(listener, nullptr);
- mClient->createComponent(listTraits[i].name.c_str(), listener,
- &component);
+ // Create component from all known services
+ component = mClient->CreateComponentByName(
+ listTraits[i].name.c_str(), listener, &mClient);
ASSERT_NE(component, nullptr) << "Create component failed for "
<< listTraits[i].name.c_str();
}
diff --git a/media/codec2/hidl/1.0/vts/functional/video/VtsHidlC2V1_0TargetVideoDecTest.cpp b/media/codec2/hidl/1.0/vts/functional/video/VtsHidlC2V1_0TargetVideoDecTest.cpp
index 8cbb7a7..dffcb6e 100644
--- a/media/codec2/hidl/1.0/vts/functional/video/VtsHidlC2V1_0TargetVideoDecTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/video/VtsHidlC2V1_0TargetVideoDecTest.cpp
@@ -421,8 +421,9 @@
ASSERT_EQ(mDisableTest, false);
}
-class Codec2VideoDecDecodeTest : public Codec2VideoDecHidlTest,
- public ::testing::WithParamInterface<int32_t> {
+class Codec2VideoDecDecodeTest
+ : public Codec2VideoDecHidlTest,
+ public ::testing::WithParamInterface<std::pair<int32_t, bool>> {
};
// Bitstream Test
@@ -430,7 +431,8 @@
description("Decodes input file");
if (mDisableTest) return;
- uint32_t streamIndex = GetParam();
+ uint32_t streamIndex = GetParam().first;
+ bool signalEOS = GetParam().second;
char mURL[512], info[512];
std::ifstream eleStream, eleInfo;
strcpy(mURL, gEnv->getRes().c_str());
@@ -464,8 +466,18 @@
ASSERT_EQ(eleStream.is_open(), true);
ASSERT_NO_FATAL_FAILURE(decodeNFrames(
mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices,
- mLinearPool, eleStream, &Info, 0, (int)Info.size()));
+ mLinearPool, eleStream, &Info, 0, (int)Info.size(), signalEOS));
+ // If EOS is not sent, sending empty input with EOS flag
+ size_t infoSize = Info.size();
+ if (!signalEOS) {
+ ASSERT_NO_FATAL_FAILURE(
+ waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue, 1));
+ ASSERT_NO_FATAL_FAILURE(
+ testInputBuffer(mComponent, mQueueLock, mWorkQueue,
+ C2FrameData::FLAG_END_OF_STREAM, false));
+ infoSize += 1;
+ }
// blocking call to ensures application to Wait till all the inputs are
// consumed
if (!mEos) {
@@ -475,19 +487,22 @@
}
eleStream.close();
- if (mFramesReceived != Info.size()) {
+ if (mFramesReceived != infoSize) {
ALOGE("Input buffer count and Output buffer count mismatch");
ALOGV("framesReceived : %d inputFrames : %zu", mFramesReceived,
- Info.size());
+ infoSize);
ASSERT_TRUE(false);
}
if (mTimestampDevTest) EXPECT_EQ(mTimestampUslist.empty(), true);
ASSERT_EQ(mComponent->stop(), C2_OK);
}
-
-INSTANTIATE_TEST_CASE_P(StreamIndexes, Codec2VideoDecDecodeTest,
- ::testing::Values(0, 1));
+// DecodeTest with StreamIndex and EOS / No EOS
+INSTANTIATE_TEST_CASE_P(StreamIndexAndEOS, Codec2VideoDecDecodeTest,
+ ::testing::Values(std::make_pair(0, false),
+ std::make_pair(0, true),
+ std::make_pair(1, false),
+ std::make_pair(1, true)));
// Adaptive Test
TEST_F(Codec2VideoDecHidlTest, AdaptiveDecodeTest) {
diff --git a/media/codec2/hidl/1.0/vts/functional/video/VtsHidlC2V1_0TargetVideoEncTest.cpp b/media/codec2/hidl/1.0/vts/functional/video/VtsHidlC2V1_0TargetVideoEncTest.cpp
index 7db41c0..673dc85 100644
--- a/media/codec2/hidl/1.0/vts/functional/video/VtsHidlC2V1_0TargetVideoEncTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/video/VtsHidlC2V1_0TargetVideoEncTest.cpp
@@ -343,13 +343,18 @@
ASSERT_EQ(mDisableTest, false);
}
-TEST_F(Codec2VideoEncHidlTest, EncodeTest) {
+class Codec2VideoEncEncodeTest : public Codec2VideoEncHidlTest,
+ public ::testing::WithParamInterface<bool> {
+};
+
+TEST_P(Codec2VideoEncEncodeTest, EncodeTest) {
description("Encodes input file");
if (mDisableTest) return;
char mURL[512];
int32_t nWidth = ENC_DEFAULT_FRAME_WIDTH;
int32_t nHeight = ENC_DEFAULT_FRAME_HEIGHT;
+ bool signalEOS = GetParam();
strcpy(mURL, gEnv->getRes().c_str());
GetURLForComponent(mURL);
@@ -367,7 +372,18 @@
ASSERT_NO_FATAL_FAILURE(
encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
mFlushedIndices, mGraphicPool, eleStream,
- 0, ENC_NUM_FRAMES, nWidth, nHeight));
+ 0, ENC_NUM_FRAMES, nWidth, nHeight, false, signalEOS));
+
+ // If EOS is not sent, sending empty input with EOS flag
+ uint32_t inputFrames = ENC_NUM_FRAMES;
+ if (!signalEOS) {
+ ASSERT_NO_FATAL_FAILURE(
+ waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue, 1));
+ ASSERT_NO_FATAL_FAILURE(
+ testInputBuffer(mComponent, mQueueLock, mWorkQueue,
+ C2FrameData::FLAG_END_OF_STREAM, false));
+ inputFrames += 1;
+ }
// blocking call to ensures application to Wait till all the inputs are
// consumed
@@ -376,10 +392,10 @@
waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
eleStream.close();
- if (mFramesReceived != ENC_NUM_FRAMES) {
+ if (mFramesReceived != inputFrames) {
ALOGE("Input buffer count and Output buffer count mismatch");
ALOGE("framesReceived : %d inputFrames : %d", mFramesReceived,
- ENC_NUM_FRAMES);
+ inputFrames);
ASSERT_TRUE(false);
}
@@ -394,6 +410,10 @@
ASSERT_EQ(mComponent->stop(), C2_OK);
}
+// EncodeTest with EOS / No EOS
+INSTANTIATE_TEST_CASE_P(EncodeTestwithEOS, Codec2VideoEncEncodeTest,
+ ::testing::Values(true, false));
+
TEST_F(Codec2VideoEncHidlTest, EOSTest) {
description("Test empty input buffer with EOS flag");
if (mDisableTest) return;
diff --git a/media/extractors/mkv/MatroskaExtractor.cpp b/media/extractors/mkv/MatroskaExtractor.cpp
index 7239302..20cc643 100644
--- a/media/extractors/mkv/MatroskaExtractor.cpp
+++ b/media/extractors/mkv/MatroskaExtractor.cpp
@@ -32,6 +32,7 @@
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaDataUtils.h>
+#include <media/stagefright/foundation/avc_utils.h>
#include <utils/String8.h>
#include <arpa/inet.h>
@@ -119,6 +120,9 @@
const mkvparser::BlockEntry *mBlockEntry;
long mBlockEntryIndex;
+ unsigned long mTrackType;
+ void seekwithoutcue_l(int64_t seekTimeUs, int64_t *actualFrameTimeUs);
+
void advance_l();
BlockIterator(const BlockIterator &);
@@ -144,6 +148,7 @@
AVC,
AAC,
HEVC,
+ MP3,
OTHER
};
@@ -156,6 +161,15 @@
List<MediaBufferHelper *> mPendingFrames;
+ int64_t mCurrentTS; // add for mp3
+ uint32_t mMP3Header;
+
+ media_status_t findMP3Header(uint32_t * header,
+ const uint8_t *dataSource, int length, int *outStartPos);
+ media_status_t mp3FrameRead(
+ MediaBufferHelper **out, const ReadOptions *options,
+ int64_t targetSampleTimeUs);
+
status_t advance();
status_t setWebmBlockCryptoInfo(MediaBufferHelper *mbuf);
@@ -222,7 +236,9 @@
mBlockIter(mExtractor,
mExtractor->mTracks.itemAt(index).mTrackNum,
index),
- mNALSizeLen(-1) {
+ mNALSizeLen(-1),
+ mCurrentTS(0),
+ mMP3Header(0) {
MatroskaExtractor::TrackInfo &trackInfo = mExtractor->mTracks.editItemAt(index);
AMediaFormat *meta = trackInfo.mMeta;
@@ -251,6 +267,8 @@
}
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
mType = AAC;
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
+ mType = MP3;
}
}
@@ -267,6 +285,16 @@
mBufferGroup->init(1 /* number of buffers */, 1024 /* buffer size */, 64 /* growth limit */);
mBlockIter.reset();
+ if (mType == MP3 && mMP3Header == 0) {
+ int start = -1;
+ media_status_t err = findMP3Header(&mMP3Header, NULL, 0, &start);
+ if (err != OK) {
+ ALOGE("No mp3 header found");
+ clearPendingFrames();
+ return err;
+ }
+ }
+
return AMEDIA_OK;
}
@@ -290,6 +318,7 @@
mCluster(NULL),
mBlockEntry(NULL),
mBlockEntryIndex(0) {
+ mTrackType = mExtractor->mSegment->GetTracks()->GetTrackByNumber(trackNum)->GetType();
reset();
}
@@ -442,12 +471,14 @@
}
if (!pCues) {
- ALOGE("No Cues in file");
+ ALOGV("No Cues in file,seek without cue data");
+ seekwithoutcue_l(seekTimeUs, actualFrameTimeUs);
return;
}
}
else if (!pSH) {
- ALOGE("No SeekHead");
+ ALOGV("No SeekHead, seek without cue data");
+ seekwithoutcue_l(seekTimeUs, actualFrameTimeUs);
return;
}
@@ -456,7 +487,9 @@
while (!pCues->DoneParsing()) {
pCues->LoadCuePoint();
pCP = pCues->GetLast();
- CHECK(pCP);
+ ALOGV("pCP = %s", pCP == NULL ? "NULL" : "not NULL");
+ if (pCP == NULL)
+ continue;
size_t trackCount = mExtractor->mTracks.size();
for (size_t index = 0; index < trackCount; ++index) {
@@ -494,6 +527,7 @@
// Always *search* based on the video track, but finalize based on mTrackNum
if (!pTP) {
ALOGE("Did not locate the video track for seeking");
+ seekwithoutcue_l(seekTimeUs, actualFrameTimeUs);
return;
}
@@ -537,6 +571,31 @@
return (mBlockEntry->GetBlock()->GetTime(mCluster) + 500ll) / 1000ll;
}
+void BlockIterator::seekwithoutcue_l(int64_t seekTimeUs, int64_t *actualFrameTimeUs) {
+ mCluster = mExtractor->mSegment->FindCluster(seekTimeUs * 1000ll);
+ const long status = mCluster->GetFirst(mBlockEntry);
+ if (status < 0) { // error
+ ALOGE("get last blockenry failed!");
+ mCluster = NULL;
+ return;
+ }
+ mBlockEntryIndex = 0;
+ while (!eos() && ((block()->GetTrackNumber() != mTrackNum) || (blockTimeUs() < seekTimeUs))) {
+ advance_l();
+ }
+
+ // video track will seek to the next key frame.
+ if (mTrackType == 1) {
+ while (!eos() && ((block()->GetTrackNumber() != mTrackNum) ||
+ !mBlockEntry->GetBlock()->IsKey())) {
+ advance_l();
+ }
+ }
+ *actualFrameTimeUs = blockTimeUs();
+ ALOGV("seekTimeUs:%lld, actualFrameTimeUs:%lld, tracknum:%lld",
+ (long long)seekTimeUs, (long long)*actualFrameTimeUs, (long long)mTrackNum);
+}
+
////////////////////////////////////////////////////////////////////////////////
static unsigned U24_AT(const uint8_t *ptr) {
@@ -762,6 +821,188 @@
return AMEDIA_OK;
}
+//the value of kMP3HeaderMask is from MP3Extractor
+static const uint32_t kMP3HeaderMask = 0xfffe0c00;
+
+media_status_t MatroskaSource::findMP3Header(uint32_t * header,
+ const uint8_t *dataSource, int length, int *outStartPos) {
+ if (NULL == header) {
+ ALOGE("header is null!");
+ return AMEDIA_ERROR_END_OF_STREAM;
+ }
+
+ //to find header start position
+ if (0 != *header) {
+ if (NULL == dataSource) {
+ *outStartPos = -1;
+ return AMEDIA_OK;
+ }
+ uint32_t tmpCode = 0;
+ for (int i = 0; i < length; i++) {
+ tmpCode = (tmpCode << 8) + dataSource[i];
+ if ((tmpCode & kMP3HeaderMask) == (*header & kMP3HeaderMask)) {
+ *outStartPos = i - 3;
+ return AMEDIA_OK;
+ }
+ }
+ *outStartPos = -1;
+ return AMEDIA_OK;
+ }
+
+ //to find mp3 header
+ uint32_t code = 0;
+ while (0 == *header) {
+ while (mPendingFrames.empty()) {
+ media_status_t err = readBlock();
+ if (err != OK) {
+ clearPendingFrames();
+ return err;
+ }
+ }
+ MediaBufferHelper *frame = *mPendingFrames.begin();
+ size_t size = frame->range_length();
+ size_t offset = frame->range_offset();
+ size_t i;
+ size_t frame_size;
+ for (i = 0; i < size; i++) {
+ ALOGV("data[%zu]=%x", i, *((uint8_t*)frame->data() + offset + i));
+ code = (code << 8) + *((uint8_t*)frame->data() + offset + i);
+ if (GetMPEGAudioFrameSize(code, &frame_size, NULL, NULL, NULL)) {
+ *header = code;
+ mBlockIter.reset();
+ clearPendingFrames();
+ return AMEDIA_OK;
+ }
+ }
+ }
+
+ return AMEDIA_ERROR_END_OF_STREAM;
+}
+
+media_status_t MatroskaSource::mp3FrameRead(
+ MediaBufferHelper **out, const ReadOptions *options,
+ int64_t targetSampleTimeUs) {
+ MediaBufferHelper *frame = *mPendingFrames.begin();
+ int64_t seekTimeUs;
+ ReadOptions::SeekMode mode;
+ if (options && options->getSeekTo(&seekTimeUs, &mode)) {
+ CHECK(AMediaFormat_getInt64(frame->meta_data(),
+ AMEDIAFORMAT_KEY_TIME_US, &mCurrentTS));
+ if (mCurrentTS < 0) {
+ mCurrentTS = 0;
+ AMediaFormat_setInt64(frame->meta_data(),
+ AMEDIAFORMAT_KEY_TIME_US, mCurrentTS);
+ }
+ }
+
+ int32_t start = -1;
+ while (start < 0) {
+ //find header start position
+ findMP3Header(&mMP3Header,
+ (const uint8_t*)frame->data() + frame->range_offset(),
+ frame->range_length(), &start);
+ ALOGV("start=%d, frame->range_length() = %zu, frame->range_offset() =%zu",
+ start, frame->range_length(), frame->range_offset());
+ if (start >= 0)
+ break;
+ frame->release();
+ mPendingFrames.erase(mPendingFrames.begin());
+ while (mPendingFrames.empty()) {
+ media_status_t err = readBlock();
+ if (err != OK) {
+ clearPendingFrames();
+ return err;
+ }
+ }
+ frame = *mPendingFrames.begin();
+ }
+
+ frame->set_range(frame->range_offset() + start, frame->range_length() - start);
+
+ uint32_t header = *(uint32_t*)((uint8_t*)frame->data() + frame->range_offset());
+ header = ((header >> 24) & 0xff) | ((header >> 8) & 0xff00) |
+ ((header << 8) & 0xff0000) | ((header << 24) & 0xff000000);
+ size_t frame_size;
+ int out_sampling_rate;
+ int out_channels;
+ int out_bitrate;
+ if (!GetMPEGAudioFrameSize(header, &frame_size,
+ &out_sampling_rate, &out_channels, &out_bitrate)) {
+ ALOGE("MP3 Header read fail!!");
+ return AMEDIA_ERROR_UNSUPPORTED;
+ }
+
+ MediaBufferHelper *buffer;
+ mBufferGroup->acquire_buffer(&buffer, false /* nonblocking */, frame_size /* requested size */);
+ buffer->set_range(0, frame_size);
+
+ uint8_t *data = static_cast<uint8_t *>(buffer->data());
+ ALOGV("MP3 frame %zu frame->range_length() %zu", frame_size, frame->range_length());
+
+ if (frame_size > frame->range_length()) {
+ memcpy(data, (uint8_t*)(frame->data()) + frame->range_offset(), frame->range_length());
+ size_t sumSize = 0;
+ sumSize += frame->range_length();
+ size_t needSize = frame_size - frame->range_length();
+ frame->release();
+ mPendingFrames.erase(mPendingFrames.begin());
+ while (mPendingFrames.empty()) {
+ media_status_t err = readBlock();
+ if (err != OK) {
+ clearPendingFrames();
+ return err;
+ }
+ }
+ frame = *mPendingFrames.begin();
+ size_t offset = frame->range_offset();
+ size_t size = frame->range_length();
+
+ // the next buffer frame is not enough to fullfill mp3 frame,
+ // we have to read until mp3 frame is completed.
+ while (size < needSize) {
+ memcpy(data + sumSize, (uint8_t*)(frame->data()) + offset, size);
+ needSize -= size;
+ sumSize += size;
+ frame->release();
+ mPendingFrames.erase(mPendingFrames.begin());
+ while (mPendingFrames.empty()) {
+ media_status_t err = readBlock();
+ if (err != OK) {
+ clearPendingFrames();
+ return err;
+ }
+ }
+ frame = *mPendingFrames.begin();
+ offset = frame->range_offset();
+ size = frame->range_length();
+ }
+ memcpy(data + sumSize, (uint8_t*)(frame->data()) + offset, needSize);
+ frame->set_range(offset + needSize, size - needSize);
+ } else {
+ size_t offset = frame->range_offset();
+ size_t size = frame->range_length();
+ memcpy(data, (uint8_t*)(frame->data()) + offset, frame_size);
+ frame->set_range(offset + frame_size, size - frame_size);
+ }
+ if (frame->range_length() < 4) {
+ frame->release();
+ frame = NULL;
+ mPendingFrames.erase(mPendingFrames.begin());
+ }
+ ALOGV("MatroskaSource::read MP3 frame kKeyTime=%lld,kKeyTargetTime=%lld",
+ (long long)mCurrentTS, (long long)targetSampleTimeUs);
+ AMediaFormat_setInt64(buffer->meta_data(),
+ AMEDIAFORMAT_KEY_TIME_US, mCurrentTS);
+ mCurrentTS += (int64_t)frame_size * 8000ll / out_bitrate;
+
+ if (targetSampleTimeUs >= 0ll)
+ AMediaFormat_setInt64(buffer->meta_data(),
+ AMEDIAFORMAT_KEY_TARGET_TIME, targetSampleTimeUs);
+ *out = buffer;
+ ALOGV("MatroskaSource::read MP3, keyTime=%lld for next frame", (long long)mCurrentTS);
+ return AMEDIA_OK;
+}
+
media_status_t MatroskaSource::read(
MediaBufferHelper **out, const ReadOptions *options) {
*out = NULL;
@@ -799,6 +1040,10 @@
}
}
+ if (mType == MP3) {
+ return mp3FrameRead(out, options, targetSampleTimeUs);
+ }
+
MediaBufferHelper *frame = *mPendingFrames.begin();
mPendingFrames.erase(mPendingFrames.begin());
@@ -924,6 +1169,59 @@
////////////////////////////////////////////////////////////////////////////////
+// trans all FOURCC to lower char
+static uint32_t FourCCtoLower(uint32_t fourcc) {
+ uint8_t ch_1 = tolower((fourcc >> 24) & 0xff);
+ uint8_t ch_2 = tolower((fourcc >> 16) & 0xff);
+ uint8_t ch_3 = tolower((fourcc >> 8) & 0xff);
+ uint8_t ch_4 = tolower((fourcc) & 0xff);
+ uint32_t fourcc_out = ch_1 << 24 | ch_2 << 16 | ch_3 << 8 | ch_4;
+
+ return fourcc_out;
+}
+
+static const char *MKVFourCC2MIME(uint32_t fourcc) {
+ ALOGV("MKVFourCC2MIME fourcc 0x%8.8x", fourcc);
+ uint32_t lowerFourcc = FourCCtoLower(fourcc);
+ switch (lowerFourcc) {
+ case FOURCC("mp4v"):
+ return MEDIA_MIMETYPE_VIDEO_MPEG4;
+
+ case FOURCC("s263"):
+ case FOURCC("h263"):
+ return MEDIA_MIMETYPE_VIDEO_H263;
+
+ case FOURCC("avc1"):
+ case FOURCC("h264"):
+ return MEDIA_MIMETYPE_VIDEO_AVC;
+
+ case FOURCC("mpg2"):
+ return MEDIA_MIMETYPE_VIDEO_MPEG2;
+
+ case FOURCC("xvid"):
+ return MEDIA_MIMETYPE_VIDEO_XVID;
+
+ case FOURCC("divx"):
+ case FOURCC("dx50"):
+ return MEDIA_MIMETYPE_VIDEO_DIVX;
+
+ case FOURCC("div3"):
+ case FOURCC("div4"):
+ return MEDIA_MIMETYPE_VIDEO_DIVX3;
+
+ case FOURCC("mjpg"):
+ case FOURCC("mppg"):
+ return MEDIA_MIMETYPE_VIDEO_MJPEG;
+
+ default:
+ char fourccString[5];
+ MakeFourCCString(fourcc, fourccString);
+ ALOGW("mkv unsupport fourcc %s", fourccString);
+ return "";
+ }
+}
+
+
MatroskaExtractor::MatroskaExtractor(DataSourceHelper *source)
: mDataSource(source),
mReader(new DataSourceBaseReader(mDataSource)),
@@ -956,17 +1254,56 @@
return;
}
- // from mkvparser::Segment::Load(), but stop at first cluster
- ret = mSegment->ParseHeaders();
- if (ret == 0) {
- long len;
- ret = mSegment->LoadCluster(pos, len);
- if (ret >= 1) {
- // no more clusters
- ret = 0;
+ if (mIsLiveStreaming) {
+ // from mkvparser::Segment::Load(), but stop at first cluster
+ ret = mSegment->ParseHeaders();
+ if (ret == 0) {
+ long len;
+ ret = mSegment->LoadCluster(pos, len);
+ if (ret >= 1) {
+ // no more clusters
+ ret = 0;
+ }
+ } else if (ret > 0) {
+ ret = mkvparser::E_BUFFER_NOT_FULL;
}
- } else if (ret > 0) {
- ret = mkvparser::E_BUFFER_NOT_FULL;
+ } else {
+ ret = mSegment->ParseHeaders();
+ if (ret < 0) {
+ ALOGE("Segment parse header return fail %lld", ret);
+ delete mSegment;
+ mSegment = NULL;
+ return;
+ } else if (ret == 0) {
+ const mkvparser::Cues* mCues = mSegment->GetCues();
+ const mkvparser::SeekHead* mSH = mSegment->GetSeekHead();
+ if ((mCues == NULL) && (mSH != NULL)) {
+ size_t count = mSH->GetCount();
+ const mkvparser::SeekHead::Entry* mEntry;
+ for (size_t index = 0; index < count; index++) {
+ mEntry = mSH->GetEntry(index);
+ if (mEntry->id == 0x0C53BB6B) { // Cues ID
+ long len;
+ long long pos;
+ mSegment->ParseCues(mEntry->pos, pos, len);
+ mCues = mSegment->GetCues();
+ ALOGV("find cue data by seekhead");
+ break;
+ }
+ }
+ }
+
+ if (mCues) {
+ long len;
+ ret = mSegment->LoadCluster(pos, len);
+ ALOGV("has Cue data, Cluster num=%ld", mSegment->GetCount());
+ } else {
+ long status_Load = mSegment->Load();
+ ALOGW("no Cue data,Segment Load status:%ld",status_Load);
+ }
+ } else if (ret > 0) {
+ ret = mkvparser::E_BUFFER_NOT_FULL;
+ }
}
if (ret < 0) {
@@ -1235,6 +1572,89 @@
return OK;
}
+status_t MatroskaExtractor::synthesizeMPEG2(TrackInfo *trackInfo, size_t index) {
+ ALOGV("synthesizeMPEG2");
+ BlockIterator iter(this, trackInfo->mTrackNum, index);
+ if (iter.eos()) {
+ return ERROR_MALFORMED;
+ }
+
+ const mkvparser::Block *block = iter.block();
+ if (block->GetFrameCount() <= 0) {
+ return ERROR_MALFORMED;
+ }
+
+ const mkvparser::Block::Frame &frame = block->GetFrame(0);
+ auto tmpData = heapbuffer<unsigned char>(frame.len);
+ long n = frame.Read(mReader, tmpData.get());
+ if (n != 0) {
+ return ERROR_MALFORMED;
+ }
+
+ size_t header_start = 0;
+ size_t header_lenth = 0;
+ for (header_start = 0; header_start < frame.len - 4; header_start++) {
+ if (ntohl(0x000001b3) == *(uint32_t*)((uint8_t*)tmpData.get() + header_start)) {
+ break;
+ }
+ }
+ bool isComplete_csd = false;
+ for (header_lenth = 0; header_lenth < frame.len - 4 - header_start; header_lenth++) {
+ if (ntohl(0x000001b8) == *(uint32_t*)((uint8_t*)tmpData.get()
+ + header_start + header_lenth)) {
+ isComplete_csd = true;
+ break;
+ }
+ }
+ if (!isComplete_csd) {
+ ALOGE("can't parse complete csd for MPEG2!");
+ return ERROR_MALFORMED;
+ }
+ addESDSFromCodecPrivate(trackInfo->mMeta, false,
+ (uint8_t*)(tmpData.get()) + header_start, header_lenth);
+
+ return OK;
+
+}
+
+status_t MatroskaExtractor::synthesizeMPEG4(TrackInfo *trackInfo, size_t index) {
+ ALOGV("synthesizeMPEG4");
+ BlockIterator iter(this, trackInfo->mTrackNum, index);
+ if (iter.eos()) {
+ return ERROR_MALFORMED;
+ }
+
+ const mkvparser::Block *block = iter.block();
+ if (block->GetFrameCount() <= 0) {
+ return ERROR_MALFORMED;
+ }
+
+ const mkvparser::Block::Frame &frame = block->GetFrame(0);
+ auto tmpData = heapbuffer<unsigned char>(frame.len);
+ long n = frame.Read(mReader, tmpData.get());
+ if (n != 0) {
+ return ERROR_MALFORMED;
+ }
+
+ size_t vosend;
+ bool isComplete_csd = false;
+ for (vosend = 0; (long)vosend < frame.len - 4; vosend++) {
+ if (ntohl(0x000001b6) == *(uint32_t*)((uint8_t*)tmpData.get() + vosend)) {
+ isComplete_csd = true;
+ break; // Send VOS until VOP
+ }
+ }
+ if (!isComplete_csd) {
+ ALOGE("can't parse complete csd for MPEG4!");
+ return ERROR_MALFORMED;
+ }
+ addESDSFromCodecPrivate(trackInfo->mMeta, false, tmpData.get(), vosend);
+
+ return OK;
+
+}
+
+
static inline bool isValidInt32ColourValue(long long value) {
return value != mkvparser::Colour::kValueNotPresent
&& value >= INT32_MIN
@@ -1417,6 +1837,8 @@
status_t err = OK;
int32_t nalSize = -1;
+ bool isSetCsdFrom1stFrame = false;
+
switch (track->GetType()) {
case VIDEO_TRACK:
{
@@ -1443,15 +1865,15 @@
continue;
}
} else if (!strcmp("V_MPEG4/ISO/ASP", codecID)) {
+ AMediaFormat_setString(meta,
+ AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_MPEG4);
if (codecPrivateSize > 0) {
- AMediaFormat_setString(meta,
- AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_MPEG4);
addESDSFromCodecPrivate(
meta, false, codecPrivate, codecPrivateSize);
} else {
ALOGW("%s is detected, but does not have configuration.",
codecID);
- continue;
+ isSetCsdFrom1stFrame = true;
}
} else if (!strcmp("V_VP8", codecID)) {
AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_VP8);
@@ -1465,6 +1887,49 @@
}
} else if (!strcmp("V_AV1", codecID)) {
AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_AV1);
+ } else if (!strcmp("V_MPEG2", codecID) || !strcmp("V_MPEG1", codecID)) {
+ AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME,
+ MEDIA_MIMETYPE_VIDEO_MPEG2);
+ if (codecPrivate != NULL) {
+ addESDSFromCodecPrivate(meta, false, codecPrivate, codecPrivateSize);
+ } else {
+ ALOGW("No specific codec private data, find it from the first frame");
+ isSetCsdFrom1stFrame = true;
+ }
+ } else if (!strcmp("V_MJPEG", codecID)) {
+ AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME,
+ MEDIA_MIMETYPE_VIDEO_MJPEG);
+ } else if (!strcmp("V_MS/VFW/FOURCC", codecID)) {
+ if (NULL == codecPrivate ||codecPrivateSize < 20) {
+ ALOGE("V_MS/VFW/FOURCC has no valid private data(%p),codecPrivateSize:%zu",
+ codecPrivate, codecPrivateSize);
+ continue;
+ } else {
+ uint32_t fourcc = *(uint32_t *)(codecPrivate + 16);
+ fourcc = ntohl(fourcc);
+ const char* mime = MKVFourCC2MIME(fourcc);
+ ALOGV("V_MS/VFW/FOURCC type is %s", mime);
+ if (!strncasecmp("video/", mime, 6)) {
+ AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, mime);
+ } else {
+ ALOGE("V_MS/VFW/FOURCC continue,unsupport video type=%s,fourcc=0x%08x.",
+ mime, fourcc);
+ continue;
+ }
+ if (!strcmp(mime, MEDIA_MIMETYPE_VIDEO_AVC) ||
+ !strcmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) ||
+ !strcmp(mime, MEDIA_MIMETYPE_VIDEO_XVID) ||
+ !strcmp(mime, MEDIA_MIMETYPE_VIDEO_DIVX) ||
+ !strcmp(mime, MEDIA_MIMETYPE_VIDEO_DIVX3) ||
+ !strcmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG2) ||
+ !strcmp(mime, MEDIA_MIMETYPE_VIDEO_H263)) {
+ isSetCsdFrom1stFrame = true;
+ } else {
+ ALOGW("FourCC have unsupport codec, type=%s,fourcc=0x%08x.",
+ mime, fourcc);
+ continue;
+ }
+ }
} else {
ALOGW("%s is not supported.", codecID);
continue;
@@ -1608,13 +2073,35 @@
initTrackInfo(track, meta, trackInfo);
trackInfo->mNalLengthSize = nalSize;
- if (!strcmp("V_MPEG4/ISO/AVC", codecID) && codecPrivateSize == 0) {
+ const char *mimetype = "";
+ AMediaFormat_getString(meta, AMEDIAFORMAT_KEY_MIME, &mimetype);
+
+ if ((!strcmp("V_MPEG4/ISO/AVC", codecID) && codecPrivateSize == 0) ||
+ (!strcmp(mimetype, MEDIA_MIMETYPE_VIDEO_AVC) && isSetCsdFrom1stFrame)) {
// Attempt to recover from AVC track without codec private data
err = synthesizeAVCC(trackInfo, n);
if (err != OK) {
mTracks.pop();
}
+ } else if ((!strcmp("V_MPEG2", codecID) && codecPrivateSize == 0) ||
+ (!strcmp(mimetype, MEDIA_MIMETYPE_VIDEO_MPEG2) && isSetCsdFrom1stFrame)) {
+ // Attempt to recover from MPEG2 track without codec private data
+ err = synthesizeMPEG2(trackInfo, n);
+ if (err != OK) {
+ mTracks.pop();
+ }
+ } else if ((!strcmp("V_MPEG4/ISO/ASP", codecID) && codecPrivateSize == 0) ||
+ (!strcmp(mimetype, MEDIA_MIMETYPE_VIDEO_MPEG4) && isSetCsdFrom1stFrame) ||
+ (!strcmp(mimetype, MEDIA_MIMETYPE_VIDEO_XVID) && isSetCsdFrom1stFrame) ||
+ (!strcmp(mimetype, MEDIA_MIMETYPE_VIDEO_DIVX) && isSetCsdFrom1stFrame) ||
+ (!strcmp(mimetype, MEDIA_MIMETYPE_VIDEO_DIVX3) && isSetCsdFrom1stFrame)) {
+ // Attempt to recover from MPEG4 track without codec private data
+ err = synthesizeMPEG4(trackInfo, n);
+ if (err != OK) {
+ mTracks.pop();
+ }
}
+
}
}
diff --git a/media/extractors/mkv/MatroskaExtractor.h b/media/extractors/mkv/MatroskaExtractor.h
index 3871bdf..d53d9e3 100644
--- a/media/extractors/mkv/MatroskaExtractor.h
+++ b/media/extractors/mkv/MatroskaExtractor.h
@@ -95,6 +95,8 @@
int64_t mSeekPreRollNs;
status_t synthesizeAVCC(TrackInfo *trackInfo, size_t index);
+ status_t synthesizeMPEG2(TrackInfo *trackInfo, size_t index);
+ status_t synthesizeMPEG4(TrackInfo *trackInfo, size_t index);
status_t initTrackInfo(
const mkvparser::Track *track,
AMediaFormat *meta,
diff --git a/media/extractors/mp4/AC4Parser.cpp b/media/extractors/mp4/AC4Parser.cpp
index 59a2e9b..13d60c8 100644
--- a/media/extractors/mp4/AC4Parser.cpp
+++ b/media/extractors/mp4/AC4Parser.cpp
@@ -260,7 +260,7 @@
int32_t short_program_id = -1;
if (bitstream_version > 1) {
- if (ac4_dsi_version == 0){
+ if (ac4_dsi_version == 0) {
ALOGE("invalid ac4 dsi");
return false;
}
@@ -295,6 +295,7 @@
bool b_single_substream_group = false;
uint32_t presentation_config = 0, presentation_version = 0;
uint32_t pres_bytes = 0;
+ uint64_t start = 0;
if (ac4_dsi_version == 0) {
CHECK_BITS_LEFT(1 + 5 + 5);
@@ -315,6 +316,8 @@
mBitReader.skipBits(pres_bytes * 8);
continue;
}
+ /* record a marker, less the size of the presentation_config */
+ start = (mDSISize - mBitReader.numBitsLeft()) / 8;
// ac4_presentation_v0_dsi(), ac4_presentation_v1_dsi() and ac4_presentation_v2_dsi()
// all start with a presentation_config of 5 bits
CHECK_BITS_LEFT(5);
@@ -338,9 +341,6 @@
(presentation_config >= NELEM(PresentationConfig) ?
"reserved" : PresentationConfig[presentation_config]));
- /* record a marker, less the size of the presentation_config */
- uint64_t start = (mDSISize - mBitReader.numBitsLeft()) / 8;
-
bool b_add_emdf_substreams = false;
if (!b_single_substream_group && presentation_config == 6) {
b_add_emdf_substreams = true;
@@ -535,14 +535,14 @@
}
break;
}
- CHECK_BITS_LEFT(1 + 1);
- bool b_pre_virtualized = (mBitReader.getBits(1) == 1);
- mPresentations[presentation].mPreVirtualized = b_pre_virtualized;
- b_add_emdf_substreams = (mBitReader.getBits(1) == 1);
- ALOGV("%u: b_pre_virtualized = %s\n", presentation, BOOLSTR(b_pre_virtualized));
- ALOGV("%u: b_add_emdf_substreams = %s\n", presentation,
- BOOLSTR(b_add_emdf_substreams));
}
+ CHECK_BITS_LEFT(1 + 1);
+ bool b_pre_virtualized = (mBitReader.getBits(1) == 1);
+ mPresentations[presentation].mPreVirtualized = b_pre_virtualized;
+ b_add_emdf_substreams = (mBitReader.getBits(1) == 1);
+ ALOGV("%u: b_pre_virtualized = %s\n", presentation, BOOLSTR(b_pre_virtualized));
+ ALOGV("%u: b_add_emdf_substreams = %s\n", presentation,
+ BOOLSTR(b_add_emdf_substreams));
}
if (b_add_emdf_substreams) {
CHECK_BITS_LEFT(7);
@@ -599,10 +599,6 @@
if (ac4_dsi_version == 1) {
uint64_t end = (mDSISize - mBitReader.numBitsLeft()) / 8;
- if (mBitReader.numBitsLeft() % 8 != 0) {
- end += 1;
- }
-
uint64_t presentation_bytes = end - start;
uint64_t skip_bytes = pres_bytes - presentation_bytes;
ALOGV("skipping = %" PRIu64 " bytes", skip_bytes);
@@ -612,7 +608,7 @@
// we should know this or something is probably wrong
// with the bitstream (or we don't support it)
- if (mPresentations[presentation].mChannelMode == -1){
+ if (mPresentations[presentation].mChannelMode == -1) {
ALOGE("could not determing channel mode of presentation %d", presentation);
return false;
}
diff --git a/media/extractors/mp4/ItemTable.cpp b/media/extractors/mp4/ItemTable.cpp
index a72e589..d56abaa 100644
--- a/media/extractors/mp4/ItemTable.cpp
+++ b/media/extractors/mp4/ItemTable.cpp
@@ -1540,7 +1540,8 @@
AMediaFormat_setInt32(meta,
AMEDIAFORMAT_KEY_THUMBNAIL_HEIGHT, thumbnail.height);
AMediaFormat_setBuffer(meta,
- AMEDIAFORMAT_KEY_CSD_HEVC, thumbnail.hvcc->data(), thumbnail.hvcc->size());
+ AMEDIAFORMAT_KEY_THUMBNAIL_CSD_HEVC,
+ thumbnail.hvcc->data(), thumbnail.hvcc->size());
ALOGV("image[%u]: thumbnail: size %dx%d, item index %zd",
imageIndex, thumbnail.width, thumbnail.height, thumbItemIndex);
} else {
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index 4298b57..22819cb 100755
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -90,7 +90,7 @@
virtual media_status_t getFormat(AMediaFormat *);
virtual media_status_t read(MediaBufferHelper **buffer, const ReadOptions *options = NULL);
- virtual bool supportNonblockingRead() { return true; }
+ bool supportsNonBlockingRead() override { return true; }
virtual media_status_t fragmentedRead(
MediaBufferHelper **buffer, const ReadOptions *options = NULL);
@@ -1487,8 +1487,13 @@
}
}
if (duration != 0 && mLastTrack->timescale != 0) {
- AMediaFormat_setInt64(mLastTrack->meta, AMEDIAFORMAT_KEY_DURATION,
- (duration * 1000000) / mLastTrack->timescale);
+ long double durationUs = ((long double)duration * 1000000) / mLastTrack->timescale;
+ if (durationUs < 0 || durationUs > INT64_MAX) {
+ ALOGE("cannot represent %lld * 1000000 / %lld in 64 bits",
+ (long long) duration, (long long) mLastTrack->timescale);
+ return ERROR_MALFORMED;
+ }
+ AMediaFormat_setInt64(mLastTrack->meta, AMEDIAFORMAT_KEY_DURATION, durationUs);
}
uint8_t lang[2];
@@ -5402,7 +5407,7 @@
break;
}
if( mode != ReadOptions::SEEK_FRAME_INDEX) {
- seekTimeUs += ((int64_t)mElstShiftStartTicks * 1000000) / mTimescale;
+ seekTimeUs += ((long double)mElstShiftStartTicks * 1000000) / mTimescale;
}
uint32_t sampleIndex;
@@ -5550,7 +5555,7 @@
AMediaFormat *meta = mBuffer->meta_data();
AMediaFormat_clear(meta);
AMediaFormat_setInt64(
- meta, AMEDIAFORMAT_KEY_TIME_US, ((int64_t)cts * 1000000) / mTimescale);
+ meta, AMEDIAFORMAT_KEY_TIME_US, ((long double)cts * 1000000) / mTimescale);
AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_IS_SYNC_FRAME, 1);
int32_t byteOrder;
@@ -5585,9 +5590,9 @@
AMediaFormat *meta = mBuffer->meta_data();
AMediaFormat_clear(meta);
AMediaFormat_setInt64(
- meta, AMEDIAFORMAT_KEY_TIME_US, ((int64_t)cts * 1000000) / mTimescale);
+ meta, AMEDIAFORMAT_KEY_TIME_US, ((long double)cts * 1000000) / mTimescale);
AMediaFormat_setInt64(
- meta, AMEDIAFORMAT_KEY_DURATION, ((int64_t)stts * 1000000) / mTimescale);
+ meta, AMEDIAFORMAT_KEY_DURATION, ((long double)stts * 1000000) / mTimescale);
if (targetSampleTimeUs >= 0) {
AMediaFormat_setInt64(
@@ -5641,9 +5646,9 @@
AMediaFormat *meta = mBuffer->meta_data();
AMediaFormat_clear(meta);
AMediaFormat_setInt64(
- meta, AMEDIAFORMAT_KEY_TIME_US, ((int64_t)cts * 1000000) / mTimescale);
+ meta, AMEDIAFORMAT_KEY_TIME_US, ((long double)cts * 1000000) / mTimescale);
AMediaFormat_setInt64(
- meta, AMEDIAFORMAT_KEY_DURATION, ((int64_t)stts * 1000000) / mTimescale);
+ meta, AMEDIAFORMAT_KEY_DURATION, ((long double)stts * 1000000) / mTimescale);
if (targetSampleTimeUs >= 0) {
AMediaFormat_setInt64(
@@ -5722,9 +5727,9 @@
AMediaFormat *meta = mBuffer->meta_data();
AMediaFormat_clear(meta);
AMediaFormat_setInt64(
- meta, AMEDIAFORMAT_KEY_TIME_US, ((int64_t)cts * 1000000) / mTimescale);
+ meta, AMEDIAFORMAT_KEY_TIME_US, ((long double)cts * 1000000) / mTimescale);
AMediaFormat_setInt64(
- meta, AMEDIAFORMAT_KEY_DURATION, ((int64_t)stts * 1000000) / mTimescale);
+ meta, AMEDIAFORMAT_KEY_DURATION, ((long double)stts * 1000000) / mTimescale);
if (targetSampleTimeUs >= 0) {
AMediaFormat_setInt64(
@@ -5771,7 +5776,7 @@
ReadOptions::SeekMode mode;
if (options && options->getSeekTo(&seekTimeUs, &mode)) {
- seekTimeUs += ((int64_t)mElstShiftStartTicks * 1000000) / mTimescale;
+ seekTimeUs += ((long double)mElstShiftStartTicks * 1000000) / mTimescale;
ALOGV("shifted seekTimeUs :%" PRId64 ", mElstShiftStartTicks:%" PRId32, seekTimeUs,
mElstShiftStartTicks);
@@ -5932,9 +5937,9 @@
CHECK(mBuffer != NULL);
mBuffer->set_range(0, size);
AMediaFormat_setInt64(bufmeta,
- AMEDIAFORMAT_KEY_TIME_US, ((int64_t)cts * 1000000) / mTimescale);
+ AMEDIAFORMAT_KEY_TIME_US, ((long double)cts * 1000000) / mTimescale);
AMediaFormat_setInt64(bufmeta,
- AMEDIAFORMAT_KEY_DURATION, ((int64_t)smpl->duration * 1000000) / mTimescale);
+ AMEDIAFORMAT_KEY_DURATION, ((long double)smpl->duration * 1000000) / mTimescale);
if (targetSampleTimeUs >= 0) {
AMediaFormat_setInt64(bufmeta, AMEDIAFORMAT_KEY_TARGET_TIME, targetSampleTimeUs);
@@ -6047,9 +6052,9 @@
AMediaFormat *bufmeta = mBuffer->meta_data();
AMediaFormat_setInt64(bufmeta,
- AMEDIAFORMAT_KEY_TIME_US, ((int64_t)cts * 1000000) / mTimescale);
+ AMEDIAFORMAT_KEY_TIME_US, ((long double)cts * 1000000) / mTimescale);
AMediaFormat_setInt64(bufmeta,
- AMEDIAFORMAT_KEY_DURATION, ((int64_t)smpl->duration * 1000000) / mTimescale);
+ AMEDIAFORMAT_KEY_DURATION, ((long double)smpl->duration * 1000000) / mTimescale);
if (targetSampleTimeUs >= 0) {
AMediaFormat_setInt64(bufmeta, AMEDIAFORMAT_KEY_TARGET_TIME, targetSampleTimeUs);
@@ -6119,6 +6124,7 @@
FOURCC("mp41"),
FOURCC("mp42"),
FOURCC("dash"),
+ FOURCC("nvr1"),
// Won't promise that the following file types can be played.
// Just give these file types a chance.
diff --git a/media/extractors/wav/WAVExtractor.cpp b/media/extractors/wav/WAVExtractor.cpp
index e58bd1f..020951b 100644
--- a/media/extractors/wav/WAVExtractor.cpp
+++ b/media/extractors/wav/WAVExtractor.cpp
@@ -81,7 +81,7 @@
virtual media_status_t read(
MediaBufferHelper **buffer, const ReadOptions *options = NULL);
- virtual bool supportNonblockingRead() { return true; }
+ bool supportsNonBlockingRead() override { return false; }
protected:
virtual ~WAVSource();
diff --git a/media/libaaudio/examples/loopback/src/loopback.cpp b/media/libaaudio/examples/loopback/src/loopback.cpp
index 6578156..c7c42eb 100644
--- a/media/libaaudio/examples/loopback/src/loopback.cpp
+++ b/media/libaaudio/examples/loopback/src/loopback.cpp
@@ -295,6 +295,7 @@
AAudioArgsParser::usage();
printf(" -B{frames} input capacity in frames\n");
printf(" -C{channels} number of input channels\n");
+ printf(" -D{deviceId} input device ID\n");
printf(" -F{0,1,2} input format, 1=I16, 2=FLOAT\n");
printf(" -g{gain} recirculating loopback gain\n");
printf(" -h{hangMillis} occasionally hang in the callback\n");
@@ -393,6 +394,7 @@
AAudioStream *outputStream = nullptr;
aaudio_result_t result = AAUDIO_OK;
+ int32_t requestedInputDeviceId = AAUDIO_UNSPECIFIED;
aaudio_sharing_mode_t requestedInputSharingMode = AAUDIO_SHARING_MODE_SHARED;
int requestedInputChannelCount = kNumInputChannels;
aaudio_format_t requestedInputFormat = AAUDIO_FORMAT_UNSPECIFIED;
@@ -431,6 +433,9 @@
case 'C':
requestedInputChannelCount = atoi(&arg[2]);
break;
+ case 'D':
+ requestedInputDeviceId = atoi(&arg[2]);
+ break;
case 'F':
requestedInputFormat = atoi(&arg[2]);
break;
@@ -529,6 +534,7 @@
printf("INPUT stream ----------------------------------------\n");
// Use different parameters for the input.
+ argParser.setDeviceId(requestedInputDeviceId);
argParser.setNumberOfBursts(AAUDIO_UNSPECIFIED);
argParser.setFormat(requestedInputFormat);
argParser.setPerformanceMode(inputPerformanceLevel);
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index baa1469..5851533 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -70,70 +70,34 @@
// ---------------------------------------------------------------------------
-static std::string audioFormatTypeString(audio_format_t value) {
- std::string formatType;
- if (FormatConverter::toString(value, formatType)) {
- return formatType;
- }
- char rawbuffer[16]; // room for "%d"
- snprintf(rawbuffer, sizeof(rawbuffer), "%d", value);
- return rawbuffer;
-}
-
-static std::string audioSourceString(audio_source_t value) {
- std::string source;
- if (SourceTypeConverter::toString(value, source)) {
- return source;
- }
- char rawbuffer[16]; // room for "%d"
- snprintf(rawbuffer, sizeof(rawbuffer), "%d", value);
- return rawbuffer;
-}
-
void AudioRecord::MediaMetrics::gather(const AudioRecord *record)
{
- // key for media statistics is defined in the header
- // attrs for media statistics
- // NB: these are matched with public Java API constants defined
- // in frameworks/base/media/java/android/media/AudioRecord.java
- // These must be kept synchronized with the constants there.
- static constexpr char kAudioRecordEncoding[] = "android.media.audiorecord.encoding";
- static constexpr char kAudioRecordSource[] = "android.media.audiorecord.source";
- static constexpr char kAudioRecordLatency[] = "android.media.audiorecord.latency";
- static constexpr char kAudioRecordSampleRate[] = "android.media.audiorecord.samplerate";
- static constexpr char kAudioRecordChannelCount[] = "android.media.audiorecord.channels";
- static constexpr char kAudioRecordCreated[] = "android.media.audiorecord.createdMs";
- static constexpr char kAudioRecordDuration[] = "android.media.audiorecord.durationMs";
- static constexpr char kAudioRecordCount[] = "android.media.audiorecord.n";
- static constexpr char kAudioRecordError[] = "android.media.audiorecord.errcode";
- static constexpr char kAudioRecordErrorFunction[] = "android.media.audiorecord.errfunc";
+#define MM_PREFIX "android.media.audiorecord." // avoid cut-n-paste errors.
- // constructor guarantees mAnalyticsItem is valid
+ // Java API 28 entries, do not change.
+ mAnalyticsItem->setCString(MM_PREFIX "encoding", toString(record->mFormat).c_str());
+ mAnalyticsItem->setCString(MM_PREFIX "source", toString(record->mAttributes.source).c_str());
+ mAnalyticsItem->setInt32(MM_PREFIX "latency", (int32_t)record->mLatency); // bad estimate.
+ mAnalyticsItem->setInt32(MM_PREFIX "samplerate", (int32_t)record->mSampleRate);
+ mAnalyticsItem->setInt32(MM_PREFIX "channels", (int32_t)record->mChannelCount);
- mAnalyticsItem->setInt32(kAudioRecordLatency, record->mLatency);
- mAnalyticsItem->setInt32(kAudioRecordSampleRate, record->mSampleRate);
- mAnalyticsItem->setInt32(kAudioRecordChannelCount, record->mChannelCount);
- mAnalyticsItem->setCString(kAudioRecordEncoding,
- audioFormatTypeString(record->mFormat).c_str());
- mAnalyticsItem->setCString(kAudioRecordSource,
- audioSourceString(record->mAttributes.source).c_str());
+ // Non-API entries, these can change.
+ mAnalyticsItem->setInt32(MM_PREFIX "portId", (int32_t)record->mPortId);
+ mAnalyticsItem->setInt32(MM_PREFIX "frameCount", (int32_t)record->mFrameCount);
+ mAnalyticsItem->setCString(MM_PREFIX "attributes", toString(record->mAttributes).c_str());
+ mAnalyticsItem->setInt64(MM_PREFIX "channelMask", (int64_t)record->mChannelMask);
- // log total duration recording, including anything currently running [and count].
- nsecs_t active = 0;
+ // log total duration recording, including anything currently running.
+ int64_t activeNs = 0;
if (mStartedNs != 0) {
- active = systemTime() - mStartedNs;
+ activeNs = systemTime() - mStartedNs;
}
- mAnalyticsItem->setInt64(kAudioRecordDuration, (mDurationNs + active) / (1000 * 1000));
- mAnalyticsItem->setInt32(kAudioRecordCount, mCount);
-
- // XXX I don't know that this adds a lot of value, long term
- if (mCreatedNs != 0) {
- mAnalyticsItem->setInt64(kAudioRecordCreated, mCreatedNs / (1000 * 1000));
- }
+ mAnalyticsItem->setDouble(MM_PREFIX "durationMs", (mDurationNs + activeNs) * 1e-6);
+ mAnalyticsItem->setInt64(MM_PREFIX "startCount", (int64_t)mCount);
if (mLastError != NO_ERROR) {
- mAnalyticsItem->setInt32(kAudioRecordError, mLastError);
- mAnalyticsItem->setCString(kAudioRecordErrorFunction, mLastErrorFunc.c_str());
+ mAnalyticsItem->setInt32(MM_PREFIX "lastError.code", (int32_t)mLastError);
+ mAnalyticsItem->setCString(MM_PREFIX "lastError.at", mLastErrorFunc.c_str());
}
}
@@ -153,7 +117,9 @@
: mActive(false), mStatus(NO_INIT), mOpPackageName(opPackageName),
mSessionId(AUDIO_SESSION_ALLOCATE),
mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT),
- mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE), mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE)
+ mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE), mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE),
+ mSelectedMicDirection(MIC_DIRECTION_UNSPECIFIED),
+ mSelectedMicFieldDimension(MIC_FIELD_DIMENSION_DEFAULT)
{
}
@@ -173,7 +139,9 @@
uid_t uid,
pid_t pid,
const audio_attributes_t* pAttributes,
- audio_port_handle_t selectedDeviceId)
+ audio_port_handle_t selectedDeviceId,
+ audio_microphone_direction_t selectedMicDirection,
+ float microphoneFieldDimension)
: mActive(false),
mStatus(NO_INIT),
mOpPackageName(opPackageName),
@@ -184,7 +152,8 @@
{
(void)set(inputSource, sampleRate, format, channelMask, frameCount, cbf, user,
notificationFrames, false /*threadCanCallJava*/, sessionId, transferType, flags,
- uid, pid, pAttributes, selectedDeviceId);
+ uid, pid, pAttributes, selectedDeviceId,
+ selectedMicDirection, microphoneFieldDimension);
}
AudioRecord::~AudioRecord()
@@ -233,7 +202,9 @@
uid_t uid,
pid_t pid,
const audio_attributes_t* pAttributes,
- audio_port_handle_t selectedDeviceId)
+ audio_port_handle_t selectedDeviceId,
+ audio_microphone_direction_t selectedMicDirection,
+ float microphoneFieldDimension)
{
status_t status = NO_ERROR;
uint32_t channelCount;
@@ -249,6 +220,8 @@
sessionId, transferType, flags, String8(mOpPackageName).string(), uid, pid);
mSelectedDeviceId = selectedDeviceId;
+ mSelectedMicDirection = selectedMicDirection;
+ mSelectedMicFieldDimension = microphoneFieldDimension;
switch (transferType) {
case TRANSFER_DEFAULT:
@@ -349,7 +322,7 @@
mCbf = cbf;
if (cbf != NULL) {
- mAudioRecordThread = new AudioRecordThread(*this, threadCanCallJava);
+ mAudioRecordThread = new AudioRecordThread(*this);
mAudioRecordThread->run("AudioRecord", ANDROID_PRIORITY_AUDIO);
// thread begins in paused state, and will not reference us until start()
}
@@ -436,6 +409,10 @@
status = restoreRecord_l("start");
}
+ // Call these directly because we are already holding the lock.
+ mAudioRecord->setMicrophoneDirection(mSelectedMicDirection);
+ mAudioRecord->setMicrophoneFieldDimension(mSelectedMicFieldDimension);
+
if (status != NO_ERROR) {
mActive = false;
ALOGE("%s(%d): status %d", __func__, mPortId, status);
@@ -653,6 +630,8 @@
mNotificationFramesAct, mNotificationFramesReq);
result.appendFormat(" input(%d), latency(%u), selected device Id(%d), routed device Id(%d)\n",
mInput, mLatency, mSelectedDeviceId, mRoutedDeviceId);
+ result.appendFormat(" mic direction(%d) mic field dimension(%f)",
+ mSelectedMicDirection, mSelectedMicFieldDimension);
::write(fd, result.string(), result.size());
return NO_ERROR;
}
@@ -1405,12 +1384,34 @@
status_t AudioRecord::setMicrophoneDirection(audio_microphone_direction_t direction)
{
AutoMutex lock(mLock);
- return mAudioRecord->setMicrophoneDirection(direction).transactionError();
+ if (mSelectedMicDirection == direction) {
+ // NOP
+ return OK;
+ }
+
+ mSelectedMicDirection = direction;
+ if (mAudioRecord == 0) {
+ // the internal AudioRecord hasn't be created yet, so just stash the attribute.
+ return OK;
+ } else {
+ return mAudioRecord->setMicrophoneDirection(direction).transactionError();
+ }
}
status_t AudioRecord::setMicrophoneFieldDimension(float zoom) {
AutoMutex lock(mLock);
- return mAudioRecord->setMicrophoneFieldDimension(zoom).transactionError();
+ if (mSelectedMicFieldDimension == zoom) {
+ // NOP
+ return OK;
+ }
+
+ mSelectedMicFieldDimension = zoom;
+ if (mAudioRecord == 0) {
+ // the internal AudioRecord hasn't be created yet, so just stash the attribute.
+ return OK;
+ } else {
+ return mAudioRecord->setMicrophoneFieldDimension(zoom).transactionError();
+ }
}
// =========================================================================
@@ -1426,8 +1427,9 @@
// =========================================================================
-AudioRecord::AudioRecordThread::AudioRecordThread(AudioRecord& receiver, bool bCanCallJava)
- : Thread(bCanCallJava), mReceiver(receiver), mPaused(true), mPausedInt(false), mPausedNs(0LL),
+AudioRecord::AudioRecordThread::AudioRecordThread(AudioRecord& receiver)
+ : Thread(true /* bCanCallJava */) // binder recursion on restoreRecord_l() may call Java.
+ , mReceiver(receiver), mPaused(true), mPausedInt(false), mPausedNs(0LL),
mIgnoreNextPausedInt(false)
{
}
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 7881bb8..e59f7e0 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -170,44 +170,8 @@
// ---------------------------------------------------------------------------
-static std::string audioContentTypeString(audio_content_type_t value) {
- std::string contentType;
- if (AudioContentTypeConverter::toString(value, contentType)) {
- return contentType;
- }
- char rawbuffer[16]; // room for "%d"
- snprintf(rawbuffer, sizeof(rawbuffer), "%d", value);
- return rawbuffer;
-}
-
-static std::string audioUsageString(audio_usage_t value) {
- std::string usage;
- if (UsageTypeConverter::toString(value, usage)) {
- return usage;
- }
- char rawbuffer[16]; // room for "%d"
- snprintf(rawbuffer, sizeof(rawbuffer), "%d", value);
- return rawbuffer;
-}
-
void AudioTrack::MediaMetrics::gather(const AudioTrack *track)
{
-
- // key for media statistics is defined in the header
- // attrs for media statistics
- // NB: these are matched with public Java API constants defined
- // in frameworks/base/media/java/android/media/AudioTrack.java
- // These must be kept synchronized with the constants there.
- static constexpr char kAudioTrackStreamType[] = "android.media.audiotrack.streamtype";
- static constexpr char kAudioTrackContentType[] = "android.media.audiotrack.type";
- static constexpr char kAudioTrackUsage[] = "android.media.audiotrack.usage";
- static constexpr char kAudioTrackSampleRate[] = "android.media.audiotrack.samplerate";
- static constexpr char kAudioTrackChannelMask[] = "android.media.audiotrack.channelmask";
-
- // NB: These are not yet exposed as public Java API constants.
- static constexpr char kAudioTrackUnderrunFrames[] = "android.media.audiotrack.underrunframes";
- static constexpr char kAudioTrackStartupGlitch[] = "android.media.audiotrack.glitch.startup";
-
// only if we're in a good state...
// XXX: shall we gather alternative info if failing?
const status_t lstatus = track->initCheck();
@@ -216,28 +180,22 @@
return;
}
- // constructor guarantees mAnalyticsItem is valid
+#define MM_PREFIX "android.media.audiotrack." // avoid cut-n-paste errors.
- const int32_t underrunFrames = track->getUnderrunFrames();
- if (underrunFrames != 0) {
- mAnalyticsItem->setInt32(kAudioTrackUnderrunFrames, underrunFrames);
- }
+ // Java API 28 entries, do not change.
+ mAnalyticsItem->setCString(MM_PREFIX "streamtype", toString(track->streamType()).c_str());
+ mAnalyticsItem->setCString(MM_PREFIX "type",
+ toString(track->mAttributes.content_type).c_str());
+ mAnalyticsItem->setCString(MM_PREFIX "usage", toString(track->mAttributes.usage).c_str());
- if (track->mTimestampStartupGlitchReported) {
- mAnalyticsItem->setInt32(kAudioTrackStartupGlitch, 1);
- }
-
- if (track->mStreamType != -1) {
- // deprecated, but this will tell us who still uses it.
- mAnalyticsItem->setInt32(kAudioTrackStreamType, track->mStreamType);
- }
- // XXX: consider including from mAttributes: source type
- mAnalyticsItem->setCString(kAudioTrackContentType,
- audioContentTypeString(track->mAttributes.content_type).c_str());
- mAnalyticsItem->setCString(kAudioTrackUsage,
- audioUsageString(track->mAttributes.usage).c_str());
- mAnalyticsItem->setInt32(kAudioTrackSampleRate, track->mSampleRate);
- mAnalyticsItem->setInt64(kAudioTrackChannelMask, track->mChannelMask);
+ // Non-API entries, these can change due to a Java string mistake.
+ mAnalyticsItem->setInt32(MM_PREFIX "sampleRate", (int32_t)track->mSampleRate);
+ mAnalyticsItem->setInt64(MM_PREFIX "channelMask", (int64_t)track->mChannelMask);
+ // Non-API entries, these can change.
+ mAnalyticsItem->setInt32(MM_PREFIX "portId", (int32_t)track->mPortId);
+ mAnalyticsItem->setCString(MM_PREFIX "encoding", toString(track->mFormat).c_str());
+ mAnalyticsItem->setInt32(MM_PREFIX "frameCount", (int32_t)track->mFrameCount);
+ mAnalyticsItem->setCString(MM_PREFIX "attributes", toString(track->mAttributes).c_str());
}
// hand the user a snapshot of the metrics.
@@ -615,7 +573,7 @@
mCbf = cbf;
if (cbf != NULL) {
- mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava);
+ mAudioTrackThread = new AudioTrackThread(*this);
mAudioTrackThread->run("AudioTrack", ANDROID_PRIORITY_AUDIO, 0 /*stack*/);
// thread begins in paused state, and will not reference us until start()
}
@@ -3127,8 +3085,9 @@
// =========================================================================
-AudioTrack::AudioTrackThread::AudioTrackThread(AudioTrack& receiver, bool bCanCallJava)
- : Thread(bCanCallJava), mReceiver(receiver), mPaused(true), mPausedInt(false), mPausedNs(0LL),
+AudioTrack::AudioTrackThread::AudioTrackThread(AudioTrack& receiver)
+ : Thread(true /* bCanCallJava */) // binder recursion on restoreTrack_l() may call Java.
+ , mReceiver(receiver), mPaused(true), mPausedInt(false), mPausedNs(0LL),
mIgnoreNextPausedInt(false)
{
}
diff --git a/media/libaudioclient/include/media/AudioMixer.h b/media/libaudioclient/include/media/AudioMixer.h
index 41b425f..783eef3 100644
--- a/media/libaudioclient/include/media/AudioMixer.h
+++ b/media/libaudioclient/include/media/AudioMixer.h
@@ -273,7 +273,7 @@
mPostDownmixReformatBufferProvider.reset(nullptr);
mDownmixerBufferProvider.reset(nullptr);
mReformatBufferProvider.reset(nullptr);
- mAdjustChannelsNonDestructiveBufferProvider.reset(nullptr);
+ mContractChannelsNonDestructiveBufferProvider.reset(nullptr);
mAdjustChannelsBufferProvider.reset(nullptr);
}
@@ -347,8 +347,12 @@
* all pre-mixer track buffer conversions outside the AudioMixer class.
*
* 1) mInputBufferProvider: The AudioTrack buffer provider.
- * 2) mAdjustChannelsBufferProvider: Expend or contracts data
- * 3) mAdjustChannelsNonDestructiveBufferProvider: Non-destructively adjust sample data
+ * 2) mAdjustChannelsBufferProvider: Expands or contracts sample data from one interleaved
+ * channel format to another. Expanded channels are filled with zeros and put at the end
+ * of each audio frame. Contracted channels are copied to the end of the buffer.
+ * 3) mContractChannelsNonDestructiveBufferProvider: Non-destructively contract sample data.
+ * This is currently using at audio-haptic coupled playback to separate audio and haptic
+ * data. Contracted channels could be written to given buffer.
* 4) mReformatBufferProvider: If not NULL, performs the audio reformat to
* match either mMixerInFormat or mDownmixRequiresFormat, if the downmixer
* requires reformat. For example, it may convert floating point input to
@@ -360,9 +364,10 @@
* 7) mTimestretchBufferProvider: Adds timestretching for playback rate
*/
AudioBufferProvider* mInputBufferProvider; // externally provided buffer provider.
- // TODO: combine AdjustChannelsBufferProvider and AdjustChannelsNonDestructiveBufferProvider
+ // TODO: combine mAdjustChannelsBufferProvider and
+ // mContractChannelsNonDestructiveBufferProvider
std::unique_ptr<PassthruBufferProvider> mAdjustChannelsBufferProvider;
- std::unique_ptr<PassthruBufferProvider> mAdjustChannelsNonDestructiveBufferProvider;
+ std::unique_ptr<PassthruBufferProvider> mContractChannelsNonDestructiveBufferProvider;
std::unique_ptr<PassthruBufferProvider> mReformatBufferProvider;
std::unique_ptr<PassthruBufferProvider> mDownmixerBufferProvider;
std::unique_ptr<PassthruBufferProvider> mPostDownmixReformatBufferProvider;
diff --git a/media/libaudioclient/include/media/AudioRecord.h b/media/libaudioclient/include/media/AudioRecord.h
index 4707c4a..b4ddb69 100644
--- a/media/libaudioclient/include/media/AudioRecord.h
+++ b/media/libaudioclient/include/media/AudioRecord.h
@@ -189,7 +189,10 @@
uid_t uid = AUDIO_UID_INVALID,
pid_t pid = -1,
const audio_attributes_t* pAttributes = NULL,
- audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE);
+ audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE,
+ audio_microphone_direction_t
+ selectedMicDirection = MIC_DIRECTION_UNSPECIFIED,
+ float selectedMicFieldDimension = MIC_FIELD_DIMENSION_DEFAULT);
/* Terminates the AudioRecord and unregisters it from AudioFlinger.
* Also destroys all resources associated with the AudioRecord.
@@ -228,7 +231,10 @@
uid_t uid = AUDIO_UID_INVALID,
pid_t pid = -1,
const audio_attributes_t* pAttributes = NULL,
- audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE);
+ audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE,
+ audio_microphone_direction_t
+ selectedMicDirection = MIC_DIRECTION_UNSPECIFIED,
+ float selectedMicFieldDimension = MIC_FIELD_DIMENSION_DEFAULT);
/* Result of constructing the AudioRecord. This must be checked for successful initialization
* before using any AudioRecord API (except for set()), because using
@@ -562,7 +568,7 @@
class AudioRecordThread : public Thread
{
public:
- AudioRecordThread(AudioRecord& receiver, bool bCanCallJava = false);
+ AudioRecordThread(AudioRecord& receiver);
// Do not call Thread::requestExitAndWait() without first calling requestExit().
// Thread::requestExitAndWait() is not virtual, and the implementation doesn't do enough.
@@ -716,6 +722,9 @@
// activity and connected devices
wp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
+ audio_microphone_direction_t mSelectedMicDirection;
+ float mSelectedMicFieldDimension;
+
private:
class MediaMetrics {
public:
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index 12f5d71..3926ead 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -934,7 +934,7 @@
class AudioTrackThread : public Thread
{
public:
- AudioTrackThread(AudioTrack& receiver, bool bCanCallJava = false);
+ AudioTrackThread(AudioTrack& receiver);
// Do not call Thread::requestExitAndWait() without first calling requestExit().
// Thread::requestExitAndWait() is not virtual, and the implementation doesn't do enough.
diff --git a/media/libaudioprocessing/AudioMixer.cpp b/media/libaudioprocessing/AudioMixer.cpp
index 2c57db7..f7cc096 100644
--- a/media/libaudioprocessing/AudioMixer.cpp
+++ b/media/libaudioprocessing/AudioMixer.cpp
@@ -408,8 +408,8 @@
void AudioMixer::Track::unprepareForAdjustChannelsNonDestructive()
{
ALOGV("AUDIOMIXER::unprepareForAdjustChannelsNonDestructive");
- if (mAdjustChannelsNonDestructiveBufferProvider.get() != nullptr) {
- mAdjustChannelsNonDestructiveBufferProvider.reset(nullptr);
+ if (mContractChannelsNonDestructiveBufferProvider.get() != nullptr) {
+ mContractChannelsNonDestructiveBufferProvider.reset(nullptr);
reconfigureBufferProviders();
}
}
@@ -426,13 +426,13 @@
? (uint8_t*)mainBuffer + frames * audio_bytes_per_frame(
mMixerChannelCount, mMixerFormat)
: NULL;
- mAdjustChannelsNonDestructiveBufferProvider.reset(
- new AdjustChannelsNonDestructiveBufferProvider(
+ mContractChannelsNonDestructiveBufferProvider.reset(
+ new AdjustChannelsBufferProvider(
mFormat,
mAdjustNonDestructiveInChannelCount,
mAdjustNonDestructiveOutChannelCount,
- mKeepContractedChannels ? mMixerFormat : AUDIO_FORMAT_INVALID,
frames,
+ mKeepContractedChannels ? mMixerFormat : AUDIO_FORMAT_INVALID,
buffer));
reconfigureBufferProviders();
}
@@ -441,9 +441,9 @@
void AudioMixer::Track::clearContractedBuffer()
{
- if (mAdjustChannelsNonDestructiveBufferProvider.get() != nullptr) {
- static_cast<AdjustChannelsNonDestructiveBufferProvider*>(
- mAdjustChannelsNonDestructiveBufferProvider.get())->clearContractedFrames();
+ if (mContractChannelsNonDestructiveBufferProvider.get() != nullptr) {
+ static_cast<AdjustChannelsBufferProvider*>(
+ mContractChannelsNonDestructiveBufferProvider.get())->clearContractedFrames();
}
}
@@ -455,9 +455,9 @@
mAdjustChannelsBufferProvider->setBufferProvider(bufferProvider);
bufferProvider = mAdjustChannelsBufferProvider.get();
}
- if (mAdjustChannelsNonDestructiveBufferProvider.get() != nullptr) {
- mAdjustChannelsNonDestructiveBufferProvider->setBufferProvider(bufferProvider);
- bufferProvider = mAdjustChannelsNonDestructiveBufferProvider.get();
+ if (mContractChannelsNonDestructiveBufferProvider.get() != nullptr) {
+ mContractChannelsNonDestructiveBufferProvider->setBufferProvider(bufferProvider);
+ bufferProvider = mContractChannelsNonDestructiveBufferProvider.get();
}
if (mReformatBufferProvider.get() != nullptr) {
mReformatBufferProvider->setBufferProvider(bufferProvider);
@@ -966,8 +966,8 @@
track->mDownmixerBufferProvider->reset();
} else if (track->mReformatBufferProvider.get() != nullptr) {
track->mReformatBufferProvider->reset();
- } else if (track->mAdjustChannelsNonDestructiveBufferProvider.get() != nullptr) {
- track->mAdjustChannelsNonDestructiveBufferProvider->reset();
+ } else if (track->mContractChannelsNonDestructiveBufferProvider.get() != nullptr) {
+ track->mContractChannelsNonDestructiveBufferProvider->reset();
} else if (track->mAdjustChannelsBufferProvider.get() != nullptr) {
track->mAdjustChannelsBufferProvider->reset();
}
diff --git a/media/libaudioprocessing/BufferProviders.cpp b/media/libaudioprocessing/BufferProviders.cpp
index b764ccb..21d25e1 100644
--- a/media/libaudioprocessing/BufferProviders.cpp
+++ b/media/libaudioprocessing/BufferProviders.cpp
@@ -627,79 +627,68 @@
}
}
-AdjustChannelsBufferProvider::AdjustChannelsBufferProvider(audio_format_t format,
- size_t inChannelCount, size_t outChannelCount, size_t frameCount) :
+AdjustChannelsBufferProvider::AdjustChannelsBufferProvider(
+ audio_format_t format, size_t inChannelCount, size_t outChannelCount,
+ size_t frameCount, audio_format_t contractedFormat, void* contractedBuffer) :
CopyBufferProvider(
audio_bytes_per_frame(inChannelCount, format),
- audio_bytes_per_frame(outChannelCount, format),
+ audio_bytes_per_frame(std::max(inChannelCount, outChannelCount), format),
frameCount),
mFormat(format),
mInChannelCount(inChannelCount),
mOutChannelCount(outChannelCount),
- mSampleSizeInBytes(audio_bytes_per_sample(format))
-{
- ALOGV("AdjustBufferProvider(%p)(%#x, %zu, %zu, %zu)",
- this, format, inChannelCount, outChannelCount, frameCount);
-}
-
-void AdjustChannelsBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
-{
- adjust_channels(src, mInChannelCount, dst, mOutChannelCount, mSampleSizeInBytes,
- frames * mInChannelCount * mSampleSizeInBytes);
-}
-
-AdjustChannelsNonDestructiveBufferProvider::AdjustChannelsNonDestructiveBufferProvider(
- audio_format_t format, size_t inChannelCount, size_t outChannelCount,
- audio_format_t contractedFormat, size_t contractedFrameCount, void* contractedBuffer) :
- CopyBufferProvider(
- audio_bytes_per_frame(std::max(inChannelCount, outChannelCount), format),
- audio_bytes_per_frame(std::max(inChannelCount, outChannelCount), format),
- contractedFrameCount),
- mFormat(format),
- mInChannelCount(inChannelCount),
- mOutChannelCount(outChannelCount),
mSampleSizeInBytes(audio_bytes_per_sample(format)),
+ mFrameCount(frameCount),
mContractedChannelCount(inChannelCount - outChannelCount),
mContractedFormat(contractedFormat),
- mContractedFrameCount(contractedFrameCount),
mContractedBuffer(contractedBuffer),
mContractedWrittenFrames(0)
{
- ALOGV("AdjustChannelsNonDestructiveBufferProvider(%p)(%#x, %zu, %zu, %#x, %p)",
- this, format, inChannelCount, outChannelCount, contractedFormat, contractedBuffer);
+ ALOGV("AdjustChannelsBufferProvider(%p)(%#x, %zu, %zu, %zu, %#x, %p)", this, format,
+ inChannelCount, outChannelCount, frameCount, contractedFormat, contractedBuffer);
if (mContractedFormat != AUDIO_FORMAT_INVALID && mInChannelCount > mOutChannelCount) {
mContractedFrameSize = audio_bytes_per_frame(mContractedChannelCount, mContractedFormat);
}
}
-status_t AdjustChannelsNonDestructiveBufferProvider::getNextBuffer(
- AudioBufferProvider::Buffer* pBuffer)
+status_t AdjustChannelsBufferProvider::getNextBuffer(AudioBufferProvider::Buffer* pBuffer)
{
- const size_t outFramesLeft = mContractedFrameCount - mContractedWrittenFrames;
- if (outFramesLeft < pBuffer->frameCount) {
- // Restrict the frame count so that we don't write over the size of the output buffer.
- pBuffer->frameCount = outFramesLeft;
+ if (mContractedBuffer != nullptr) {
+ // Restrict frame count only when it is needed to save contracted frames.
+ const size_t outFramesLeft = mFrameCount - mContractedWrittenFrames;
+ if (outFramesLeft < pBuffer->frameCount) {
+ // Restrict the frame count so that we don't write over the size of the output buffer.
+ pBuffer->frameCount = outFramesLeft;
+ }
}
return CopyBufferProvider::getNextBuffer(pBuffer);
}
-void AdjustChannelsNonDestructiveBufferProvider::copyFrames(
- void *dst, const void *src, size_t frames)
+void AdjustChannelsBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
{
- adjust_channels_non_destructive(src, mInChannelCount, dst, mOutChannelCount, mSampleSizeInBytes,
- frames * mInChannelCount * mSampleSizeInBytes);
- if (mContractedFormat != AUDIO_FORMAT_INVALID && mContractedBuffer != NULL
- && mInChannelCount > mOutChannelCount) {
- const size_t contractedIdx = frames * mOutChannelCount * mSampleSizeInBytes;
- memcpy_by_audio_format(
- (uint8_t*)mContractedBuffer + mContractedWrittenFrames * mContractedFrameSize,
- mContractedFormat, (uint8_t*)dst + contractedIdx, mFormat,
- mContractedChannelCount * frames);
- mContractedWrittenFrames += frames;
+ if (mInChannelCount > mOutChannelCount) {
+ // For case multi to mono, adjust_channels has special logic that will mix first two input
+ // channels into a single output channel. In that case, use adjust_channels_non_destructive
+ // to keep only one channel data even when contracting to mono.
+ adjust_channels_non_destructive(src, mInChannelCount, dst, mOutChannelCount,
+ mSampleSizeInBytes, frames * mInChannelCount * mSampleSizeInBytes);
+ if (mContractedFormat != AUDIO_FORMAT_INVALID
+ && mContractedBuffer != nullptr) {
+ const size_t contractedIdx = frames * mOutChannelCount * mSampleSizeInBytes;
+ memcpy_by_audio_format(
+ (uint8_t*) mContractedBuffer + mContractedWrittenFrames * mContractedFrameSize,
+ mContractedFormat, (uint8_t*) dst + contractedIdx, mFormat,
+ mContractedChannelCount * frames);
+ mContractedWrittenFrames += frames;
+ }
+ } else {
+ // Prefer expanding data from the end of each audio frame.
+ adjust_channels(src, mInChannelCount, dst, mOutChannelCount,
+ mSampleSizeInBytes, frames * mInChannelCount * mSampleSizeInBytes);
}
}
-void AdjustChannelsNonDestructiveBufferProvider::reset()
+void AdjustChannelsBufferProvider::reset()
{
mContractedWrittenFrames = 0;
CopyBufferProvider::reset();
diff --git a/media/libeffects/downmix/tests/Android.bp b/media/libeffects/downmix/tests/Android.bp
index e2e7dbd..63afc54 100644
--- a/media/libeffects/downmix/tests/Android.bp
+++ b/media/libeffects/downmix/tests/Android.bp
@@ -24,7 +24,6 @@
],
cflags: [
- "-v",
"-Werror",
"-Wextra",
],
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 9799cad..a529628 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -1,3 +1,10 @@
+cc_defaults {
+ name: "libmedia_defaults",
+ include_dirs: [
+ "bionic/libc/private",
+ ],
+}
+
cc_library_headers {
name: "libmedia_headers",
vendor_available: true,
@@ -86,6 +93,7 @@
export_shared_lib_headers: [
"android.hidl.token@1.0-utils",
"android.hardware.media.omx@1.0",
+ "libgui",
"libstagefright_foundation",
"libui",
],
@@ -148,6 +156,8 @@
cc_library {
name: "libmedia",
+ defaults: [ "libmedia_defaults" ],
+
srcs: [
"IDataSource.cpp",
"BufferingSettings.cpp",
@@ -258,6 +268,8 @@
cc_library_static {
name: "libmedia_player2_util",
+ defaults: [ "libmedia_defaults" ],
+
srcs: [
"AudioParameter.cpp",
"BufferingSettings.cpp",
diff --git a/media/libmedia/IMediaRecorder.cpp b/media/libmedia/IMediaRecorder.cpp
index 56ee18e..f283569 100644
--- a/media/libmedia/IMediaRecorder.cpp
+++ b/media/libmedia/IMediaRecorder.cpp
@@ -66,6 +66,8 @@
ENABLE_AUDIO_DEVICE_CALLBACK,
GET_ACTIVE_MICROPHONES,
GET_PORT_ID,
+ SET_MICROPHONE_DIRECTION,
+ SET_MICROPHONE_FIELD_DIMENSION
};
class BpMediaRecorder: public BpInterface<IMediaRecorder>
@@ -407,6 +409,24 @@
return status;
}
+ status_t setMicrophoneDirection(audio_microphone_direction_t direction) {
+ ALOGV("setMicrophoneDirection(%d)", direction);
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+ data.writeInt32(direction);
+ status_t status = remote()->transact(SET_MICROPHONE_DIRECTION, data, &reply);
+ return status == NO_ERROR ? (status_t)reply.readInt32() : status;
+ }
+
+ status_t setMicrophoneFieldDimension(float zoom) {
+ ALOGV("setMicrophoneFieldDimension(%f)", zoom);
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+ data.writeFloat(zoom);
+ status_t status = remote()->transact(SET_MICROPHONE_FIELD_DIMENSION, data, &reply);
+ return status == NO_ERROR ? (status_t)reply.readInt32() : status;
+ }
+
status_t getPortId(audio_port_handle_t *portId)
{
ALOGV("getPortId");
@@ -689,6 +709,23 @@
}
return NO_ERROR;
}
+ case SET_MICROPHONE_DIRECTION: {
+ ALOGV("SET_MICROPHONE_DIRECTION");
+ CHECK_INTERFACE(IMediaRecorder, data, reply);
+ int direction = data.readInt32();
+ status_t status =
+ setMicrophoneDirection(static_cast<audio_microphone_direction_t>(direction));
+ reply->writeInt32(status);
+ return NO_ERROR;
+ }
+ case SET_MICROPHONE_FIELD_DIMENSION: {
+ ALOGV("SET_MICROPHONE_FIELD_DIMENSION");
+ CHECK_INTERFACE(IMediaRecorder, data, reply);
+ float zoom = data.readFloat();
+ status_t status = setMicrophoneFieldDimension(zoom);
+ reply->writeInt32(status);
+ return NO_ERROR;
+ }
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/media/libmedia/MediaUtils.cpp b/media/libmedia/MediaUtils.cpp
index bcc7ebf..31972fa 100644
--- a/media/libmedia/MediaUtils.cpp
+++ b/media/libmedia/MediaUtils.cpp
@@ -22,23 +22,16 @@
#include <sys/resource.h>
#include <unistd.h>
+#include <bionic_malloc.h>
+
#include "MediaUtils.h"
-extern "C" size_t __cfi_shadow_size();
extern "C" void __scudo_set_rss_limit(size_t, int) __attribute__((weak));
namespace android {
-void limitProcessMemory(
- const char *property,
- size_t numberOfBytes,
- size_t percentageOfTotalMem) {
-
- if (running_with_asan()) {
- ALOGW("Running with (HW)ASan, skip enforcing memory limitations.");
- return;
- }
-
+void limitProcessMemory(const char *property, size_t numberOfBytes,
+ size_t percentageOfTotalMem) {
long pageSize = sysconf(_SC_PAGESIZE);
long numPages = sysconf(_SC_PHYS_PAGES);
size_t maxMem = SIZE_MAX;
@@ -66,38 +59,17 @@
maxMem = propVal;
}
- // If 64-bit Scudo is in use, enforce the hard RSS limit (in MB).
- if (maxMem != SIZE_MAX && sizeof(void *) == 8 &&
- &__scudo_set_rss_limit != 0) {
+ // If Scudo is in use, enforce the hard RSS limit (in MB).
+ if (maxMem != SIZE_MAX && &__scudo_set_rss_limit != 0) {
__scudo_set_rss_limit(maxMem >> 20, 1);
ALOGV("Scudo hard RSS limit set to %zu MB", maxMem >> 20);
return;
}
- // Increase by the size of the CFI shadow mapping. Most of the shadow is not
- // backed with physical pages, and it is possible for the result to be
- // higher than total physical memory. This is fine for RLIMIT_AS.
- size_t cfi_size = __cfi_shadow_size();
- if (cfi_size) {
- ALOGV("cfi shadow size: %zu", cfi_size);
- if (maxMem <= SIZE_MAX - cfi_size) {
- maxMem += cfi_size;
- } else {
- maxMem = SIZE_MAX;
- }
+ if (!android_mallopt(M_SET_ALLOCATION_LIMIT_BYTES, &maxMem,
+ sizeof(maxMem))) {
+ ALOGW("couldn't set allocation limit");
}
- ALOGV("actual limit: %zu", maxMem);
-
- struct rlimit limit;
- getrlimit(RLIMIT_AS, &limit);
- ALOGV("original limits: %lld/%lld", (long long)limit.rlim_cur, (long long)limit.rlim_max);
- limit.rlim_cur = maxMem;
- setrlimit(RLIMIT_AS, &limit);
- limit.rlim_cur = -1;
- limit.rlim_max = -1;
- getrlimit(RLIMIT_AS, &limit);
- ALOGV("new limits: %lld/%lld", (long long)limit.rlim_cur, (long long)limit.rlim_max);
-
}
} // namespace android
diff --git a/media/libmedia/MediaUtils.h b/media/libmedia/MediaUtils.h
index 26075c4..f80dd30 100644
--- a/media/libmedia/MediaUtils.h
+++ b/media/libmedia/MediaUtils.h
@@ -19,13 +19,6 @@
namespace android {
-extern "C" void __asan_init(void) __attribute__((weak));
-extern "C" void __hwasan_init(void) __attribute__((weak));
-
-static inline int running_with_asan() {
- return &__asan_init != 0 || &__hwasan_init != 0;
-}
-
/**
Limit the amount of memory a process can allocate using setrlimit(RLIMIT_AS).
The value to use will be read from the specified system property, or if the
diff --git a/media/libmedia/TypeConverter.cpp b/media/libmedia/TypeConverter.cpp
index 0301b21..469c5b6 100644
--- a/media/libmedia/TypeConverter.cpp
+++ b/media/libmedia/TypeConverter.cpp
@@ -217,6 +217,7 @@
MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_APTX_ADAPTIVE),
MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_LHDC),
MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_LHDC_LL),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_APTX_TWSP),
TERMINATOR
};
diff --git a/media/libmedia/include/media/BufferProviders.h b/media/libmedia/include/media/BufferProviders.h
index ea41527..b038854 100644
--- a/media/libmedia/include/media/BufferProviders.h
+++ b/media/libmedia/include/media/BufferProviders.h
@@ -218,33 +218,21 @@
bool mAudioPlaybackRateValid; // flag for current parameters validity
};
-// AdjustBufferProvider derives from CopyBufferProvider to adjust sample data.
+// AdjustChannelsBufferProvider derives from CopyBufferProvider to adjust sample data.
// Expands or contracts sample data from one interleaved channel format to another.
-// Expanded channels are filled with zeros and put at the end of each audio frame.
-// Contracted channels are omitted from the end of each audio frame.
+// Extra expanded channels are filled with zeros and put at the end of each audio frame.
+// Contracted channels are copied to the end of the output buffer(storage should be
+// allocated appropriately).
+// Contracted channels could be written to output buffer.
class AdjustChannelsBufferProvider : public CopyBufferProvider {
public:
AdjustChannelsBufferProvider(audio_format_t format, size_t inChannelCount,
- size_t outChannelCount, size_t frameCount);
- //Overrides
- void copyFrames(void *dst, const void *src, size_t frames) override;
-
-protected:
- const audio_format_t mFormat;
- const size_t mInChannelCount;
- const size_t mOutChannelCount;
- const size_t mSampleSizeInBytes;
-};
-
-// AdjustChannelsNonDestructiveBufferProvider derives from CopyBufferProvider to adjust sample data.
-// Expands or contracts sample data from one interleaved channel format to another.
-// Extra expanded channels are interleaved in from the end of the input buffer.
-// Contracted channels are copied to the end of the output buffer.
-// Contracted channels could be written to output buffer.
-class AdjustChannelsNonDestructiveBufferProvider : public CopyBufferProvider {
-public:
- AdjustChannelsNonDestructiveBufferProvider(audio_format_t format, size_t inChannelCount,
- size_t outChannelCount, audio_format_t contractedFormat, size_t contractedFrameCount,
+ size_t outChannelCount, size_t frameCount) : AdjustChannelsBufferProvider(
+ format, inChannelCount, outChannelCount,
+ frameCount, AUDIO_FORMAT_INVALID, nullptr) { }
+ // Contracted data is converted to contractedFormat and put into contractedBuffer.
+ AdjustChannelsBufferProvider(audio_format_t format, size_t inChannelCount,
+ size_t outChannelCount, size_t frameCount, audio_format_t contractedFormat,
void* contractedBuffer);
//Overrides
status_t getNextBuffer(Buffer* pBuffer) override;
@@ -258,9 +246,9 @@
const size_t mInChannelCount;
const size_t mOutChannelCount;
const size_t mSampleSizeInBytes;
+ const size_t mFrameCount;
const size_t mContractedChannelCount;
const audio_format_t mContractedFormat;
- const size_t mContractedFrameCount;
void *mContractedBuffer;
size_t mContractedWrittenFrames;
size_t mContractedFrameSize;
diff --git a/media/libmedia/include/media/IMediaRecorder.h b/media/libmedia/include/media/IMediaRecorder.h
index e7c466d..0b09420 100644
--- a/media/libmedia/include/media/IMediaRecorder.h
+++ b/media/libmedia/include/media/IMediaRecorder.h
@@ -73,6 +73,8 @@
virtual status_t enableAudioDeviceCallback(bool enabled) = 0;
virtual status_t getActiveMicrophones(
std::vector<media::MicrophoneInfo>* activeMicrophones) = 0;
+ virtual status_t setMicrophoneDirection(audio_microphone_direction_t direction) = 0;
+ virtual status_t setMicrophoneFieldDimension(float zoom) = 0;
virtual status_t getPortId(audio_port_handle_t *portId) = 0;
};
diff --git a/media/libmedia/include/media/IMediaSource.h b/media/libmedia/include/media/IMediaSource.h
index 7a4b1b9..5ab6e37 100644
--- a/media/libmedia/include/media/IMediaSource.h
+++ b/media/libmedia/include/media/IMediaSource.h
@@ -126,8 +126,8 @@
static const size_t kBinderMediaBuffers = 4; // buffers managed by BnMediaSource
static const size_t kTransferSharedAsSharedThreshold = 4 * 1024; // if >= shared, else inline
- static const size_t kTransferInlineAsSharedThreshold = 64 * 1024; // if >= shared, else inline
- static const size_t kInlineMaxTransfer = 256 * 1024; // Binder size limited to BINDER_VM_SIZE.
+ static const size_t kTransferInlineAsSharedThreshold = 8 * 1024; // if >= shared, else inline
+ static const size_t kInlineMaxTransfer = 64 * 1024; // Binder size limited to BINDER_VM_SIZE.
protected:
virtual ~BnMediaSource();
diff --git a/media/libmedia/include/media/MediaRecorderBase.h b/media/libmedia/include/media/MediaRecorderBase.h
index e1c5d47..88282ac 100644
--- a/media/libmedia/include/media/MediaRecorderBase.h
+++ b/media/libmedia/include/media/MediaRecorderBase.h
@@ -72,6 +72,8 @@
virtual status_t enableAudioDeviceCallback(bool enabled) = 0;
virtual status_t getActiveMicrophones(
std::vector<media::MicrophoneInfo>* activeMicrophones) = 0;
+ virtual status_t setMicrophoneDirection(audio_microphone_direction_t direction) = 0;
+ virtual status_t setMicrophoneFieldDimension(float zoom) = 0;
virtual status_t getPortId(audio_port_handle_t *portId) const = 0;
diff --git a/media/libmedia/include/media/mediarecorder.h b/media/libmedia/include/media/mediarecorder.h
index 33be559..8580437 100644
--- a/media/libmedia/include/media/mediarecorder.h
+++ b/media/libmedia/include/media/mediarecorder.h
@@ -264,6 +264,9 @@
status_t getRoutedDeviceId(audio_port_handle_t *deviceId);
status_t enableAudioDeviceCallback(bool enabled);
status_t getActiveMicrophones(std::vector<media::MicrophoneInfo>* activeMicrophones);
+ status_t setMicrophoneDirection(audio_microphone_direction_t direction);
+ status_t setMicrophoneFieldDimension(float zoom);
+
status_t getPortId(audio_port_handle_t *portId) const;
private:
diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp
index d07e703..6c59a29 100644
--- a/media/libmedia/mediarecorder.cpp
+++ b/media/libmedia/mediarecorder.cpp
@@ -842,6 +842,16 @@
return mMediaRecorder->getActiveMicrophones(activeMicrophones);
}
+status_t MediaRecorder::setMicrophoneDirection(audio_microphone_direction_t direction) {
+ ALOGV("setMicrophoneDirection(%d)", direction);
+ return mMediaRecorder->setMicrophoneDirection(direction);
+}
+
+status_t MediaRecorder::setMicrophoneFieldDimension(float zoom) {
+ ALOGV("setMicrophoneFieldDimension(%f)", zoom);
+ return mMediaRecorder->setMicrophoneFieldDimension(zoom);
+}
+
status_t MediaRecorder::getPortId(audio_port_handle_t *portId) const
{
ALOGV("getPortId");
diff --git a/media/libmedia/xsd/Android.bp b/media/libmedia/xsd/Android.bp
new file mode 100644
index 0000000..1635f70
--- /dev/null
+++ b/media/libmedia/xsd/Android.bp
@@ -0,0 +1,21 @@
+//
+// Copyright (C) 2019 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.
+//
+
+xsd_config {
+ name: "media_profiles",
+ srcs: ["media_profiles.xsd"],
+ package_name: "media.profiles",
+}
diff --git a/media/libmedia/xsd/api/current.txt b/media/libmedia/xsd/api/current.txt
new file mode 100644
index 0000000..0924dd9
--- /dev/null
+++ b/media/libmedia/xsd/api/current.txt
@@ -0,0 +1,140 @@
+// Signature format: 2.0
+package media.profiles {
+
+ public class Audio {
+ ctor public Audio();
+ method public int getBitRate();
+ method public int getChannels();
+ method public String getCodec();
+ method public int getSampleRate();
+ method public void setBitRate(int);
+ method public void setChannels(int);
+ method public void setCodec(String);
+ method public void setSampleRate(int);
+ }
+
+ public class AudioDecoderCap {
+ ctor public AudioDecoderCap();
+ method public boolean getEnabled();
+ method public String getName();
+ method public void setEnabled(boolean);
+ method public void setName(String);
+ }
+
+ public class AudioEncoderCap {
+ ctor public AudioEncoderCap();
+ method public boolean getEnabled();
+ method public int getMaxBitRate();
+ method public int getMaxChannels();
+ method public int getMaxSampleRate();
+ method public int getMinBitRate();
+ method public int getMinChannels();
+ method public int getMinSampleRate();
+ method public String getName();
+ method public void setEnabled(boolean);
+ method public void setMaxBitRate(int);
+ method public void setMaxChannels(int);
+ method public void setMaxSampleRate(int);
+ method public void setMinBitRate(int);
+ method public void setMinChannels(int);
+ method public void setMinSampleRate(int);
+ method public void setName(String);
+ }
+
+ public class CamcorderProfiles {
+ ctor public CamcorderProfiles();
+ method public int getCameraId();
+ method public java.util.List<media.profiles.EncoderProfile> getEncoderProfile();
+ method public java.util.List<media.profiles.CamcorderProfiles.ImageEncoding> getImageEncoding();
+ method public void setCameraId(int);
+ }
+
+ public static class CamcorderProfiles.ImageEncoding {
+ ctor public CamcorderProfiles.ImageEncoding();
+ method public int getQuality();
+ method public void setQuality(int);
+ }
+
+ public class EncoderProfile {
+ ctor public EncoderProfile();
+ method public java.util.List<media.profiles.Audio> getAudio();
+ method public int getDuration();
+ method public String getFileFormat();
+ method public String getQuality();
+ method public java.util.List<media.profiles.Video> getVideo();
+ method public void setDuration(int);
+ method public void setFileFormat(String);
+ method public void setQuality(String);
+ }
+
+ public class MediaSettings {
+ ctor public MediaSettings();
+ method public java.util.List<media.profiles.AudioDecoderCap> getAudioDecoderCap();
+ method public java.util.List<media.profiles.AudioEncoderCap> getAudioEncoderCap();
+ method public java.util.List<media.profiles.CamcorderProfiles> getCamcorderProfiles();
+ method public java.util.List<media.profiles.MediaSettings.EncoderOutputFileFormat> getEncoderOutputFileFormat();
+ method public java.util.List<media.profiles.VideoDecoderCap> getVideoDecoderCap();
+ method public java.util.List<media.profiles.VideoEncoderCap> getVideoEncoderCap();
+ }
+
+ public static class MediaSettings.EncoderOutputFileFormat {
+ ctor public MediaSettings.EncoderOutputFileFormat();
+ method public String getName();
+ method public void setName(String);
+ }
+
+ public class Video {
+ ctor public Video();
+ method public int getBitRate();
+ method public String getCodec();
+ method public int getFrameRate();
+ method public int getHeight();
+ method public int getWidth();
+ method public void setBitRate(int);
+ method public void setCodec(String);
+ method public void setFrameRate(int);
+ method public void setHeight(int);
+ method public void setWidth(int);
+ }
+
+ public class VideoDecoderCap {
+ ctor public VideoDecoderCap();
+ method public boolean getEnabled();
+ method public String getName();
+ method public void setEnabled(boolean);
+ method public void setName(String);
+ }
+
+ public class VideoEncoderCap {
+ ctor public VideoEncoderCap();
+ method public boolean getEnabled();
+ method public int getMaxBitRate();
+ method public int getMaxFrameHeight();
+ method public int getMaxFrameRate();
+ method public int getMaxFrameWidth();
+ method public int getMinBitRate();
+ method public int getMinFrameHeight();
+ method public int getMinFrameRate();
+ method public int getMinFrameWidth();
+ method public String getName();
+ method public void setEnabled(boolean);
+ method public void setMaxBitRate(int);
+ method public void setMaxFrameHeight(int);
+ method public void setMaxFrameRate(int);
+ method public void setMaxFrameWidth(int);
+ method public void setMinBitRate(int);
+ method public void setMinFrameHeight(int);
+ method public void setMinFrameRate(int);
+ method public void setMinFrameWidth(int);
+ method public void setName(String);
+ }
+
+ public class XmlParser {
+ ctor public XmlParser();
+ method public static media.profiles.MediaSettings read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ }
+
+}
+
diff --git a/media/libmedia/xsd/api/last_current.txt b/media/libmedia/xsd/api/last_current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/media/libmedia/xsd/api/last_current.txt
diff --git a/media/libmedia/xsd/api/last_removed.txt b/media/libmedia/xsd/api/last_removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/media/libmedia/xsd/api/last_removed.txt
diff --git a/media/libmedia/xsd/api/removed.txt b/media/libmedia/xsd/api/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/media/libmedia/xsd/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/media/libmedia/xsd/media_profiles.xsd b/media/libmedia/xsd/media_profiles.xsd
new file mode 100644
index 0000000..a9687b0
--- /dev/null
+++ b/media/libmedia/xsd/media_profiles.xsd
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+<!-- TODO: define a targetNamespace. Note that it will break retrocompatibility -->
+<xs:schema version="2.0"
+ elementFormDefault="qualified"
+ attributeFormDefault="unqualified"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:element name="MediaSettings">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="CamcorderProfiles" type="CamcorderProfiles" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="EncoderOutputFileFormat" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:attribute name="name" type="xs:string"/>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="VideoEncoderCap" type="VideoEncoderCap" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="AudioEncoderCap" type="AudioEncoderCap" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="VideoDecoderCap" type="VideoDecoderCap" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="AudioDecoderCap" type="AudioDecoderCap" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:complexType name="CamcorderProfiles">
+ <xs:sequence>
+ <xs:element name="EncoderProfile" type="EncoderProfile" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="ImageEncoding" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:attribute name="quality" type="xs:int"/>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ <xs:attribute name="cameraId" type="xs:int"/>
+ </xs:complexType>
+ <xs:complexType name="EncoderProfile">
+ <xs:sequence>
+ <xs:element name="Video" type="Video" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="Audio" type="Audio" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="quality" type="xs:string"/>
+ <xs:attribute name="fileFormat" type="xs:string"/>
+ <xs:attribute name="duration" type="xs:int"/>
+ </xs:complexType>
+ <xs:complexType name="Video">
+ <xs:attribute name="codec" type="xs:string"/>
+ <xs:attribute name="bitRate" type="xs:int"/>
+ <xs:attribute name="width" type="xs:int"/>
+ <xs:attribute name="height" type="xs:int"/>
+ <xs:attribute name="frameRate" type="xs:int"/>
+ </xs:complexType>
+ <xs:complexType name="Audio">
+ <xs:attribute name="codec" type="xs:string"/>
+ <xs:attribute name="bitRate" type="xs:int"/>
+ <xs:attribute name="sampleRate" type="xs:int"/>
+ <xs:attribute name="channels" type="xs:int"/>
+ </xs:complexType>
+ <xs:complexType name="VideoEncoderCap">
+ <xs:attribute name="name" type="xs:string"/>
+ <xs:attribute name="enabled" type="xs:boolean"/>
+ <xs:attribute name="minBitRate" type="xs:int"/>
+ <xs:attribute name="maxBitRate" type="xs:int"/>
+ <xs:attribute name="minFrameWidth" type="xs:int"/>
+ <xs:attribute name="maxFrameWidth" type="xs:int"/>
+ <xs:attribute name="minFrameHeight" type="xs:int"/>
+ <xs:attribute name="maxFrameHeight" type="xs:int"/>
+ <xs:attribute name="minFrameRate" type="xs:int"/>
+ <xs:attribute name="maxFrameRate" type="xs:int"/>
+ </xs:complexType>
+ <xs:complexType name="AudioEncoderCap">
+ <xs:attribute name="name" type="xs:string"/>
+ <xs:attribute name="enabled" type="xs:boolean"/>
+ <xs:attribute name="minBitRate" type="xs:int"/>
+ <xs:attribute name="maxBitRate" type="xs:int"/>
+ <xs:attribute name="minSampleRate" type="xs:int"/>
+ <xs:attribute name="maxSampleRate" type="xs:int"/>
+ <xs:attribute name="minChannels" type="xs:int"/>
+ <xs:attribute name="maxChannels" type="xs:int"/>
+ </xs:complexType>
+ <xs:complexType name="VideoDecoderCap">
+ <xs:attribute name="name" type="xs:string"/>
+ <xs:attribute name="enabled" type="xs:boolean"/>
+ </xs:complexType>
+ <xs:complexType name="AudioDecoderCap">
+ <xs:attribute name="name" type="xs:string"/>
+ <xs:attribute name="enabled" type="xs:boolean"/>
+ </xs:complexType>
+</xs:schema>
diff --git a/media/libmediaplayer2/JAudioTrack.cpp b/media/libmediaplayer2/JAudioTrack.cpp
index a01afa3..fab6c64 100644
--- a/media/libmediaplayer2/JAudioTrack.cpp
+++ b/media/libmediaplayer2/JAudioTrack.cpp
@@ -571,10 +571,9 @@
}
void JAudioTrack::registerRoutingDelegates(
- std::vector<std::pair<jobject, jobject>>& routingDelegates) {
- for (std::vector<std::pair<jobject, jobject>>::iterator it = routingDelegates.begin();
- it != routingDelegates.end(); it++) {
- addAudioDeviceCallback(it->second, getHandler(it->second));
+ Vector<std::pair<sp<JObjectHolder>, sp<JObjectHolder>>>& routingDelegates) {
+ for (auto it = routingDelegates.begin(); it != routingDelegates.end(); it++) {
+ addAudioDeviceCallback(it->second->getJObject(), getHandler(it->second->getJObject()));
}
}
@@ -597,34 +596,22 @@
return env->CallObjectMethod(routingDelegateObj, jGetHandler);
}
-jobject JAudioTrack::addGlobalRef(const jobject obj) {
+jobject JAudioTrack::findByKey(
+ Vector<std::pair<sp<JObjectHolder>, sp<JObjectHolder>>>& mp, const jobject key) {
JNIEnv *env = JavaVMHelper::getJNIEnv();
- return reinterpret_cast<jobject>(env->NewGlobalRef(obj));
-}
-
-status_t JAudioTrack::removeGlobalRef(const jobject obj) {
- if (obj == NULL) {
- return BAD_VALUE;
- }
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- env->DeleteGlobalRef(obj);
- return NO_ERROR;
-}
-
-jobject JAudioTrack::findByKey(std::vector<std::pair<jobject, jobject>>& mp, const jobject key) {
- JNIEnv *env = JavaVMHelper::getJNIEnv();
- for (std::vector<std::pair<jobject, jobject>>::iterator it = mp.begin(); it != mp.end(); it++) {
- if (env->IsSameObject(it->first, key)) {
- return it->second;
+ for (auto it = mp.begin(); it != mp.end(); it++) {
+ if (env->IsSameObject(it->first->getJObject(), key)) {
+ return it->second->getJObject();
}
}
return nullptr;
}
-void JAudioTrack::eraseByKey(std::vector<std::pair<jobject, jobject>>& mp, const jobject key) {
+void JAudioTrack::eraseByKey(
+ Vector<std::pair<sp<JObjectHolder>, sp<JObjectHolder>>>& mp, const jobject key) {
JNIEnv *env = JavaVMHelper::getJNIEnv();
- for (std::vector<std::pair<jobject, jobject>>::iterator it = mp.begin(); it != mp.end(); it++) {
- if (env->IsSameObject(it->first, key)) {
+ for (auto it = mp.begin(); it != mp.end(); it++) {
+ if (env->IsSameObject(it->first->getJObject(), key)) {
mp.erase(it);
return;
}
diff --git a/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp b/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
index 4de92ad..b4fa0c1 100644
--- a/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
+++ b/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
@@ -85,9 +85,6 @@
}
MediaPlayer2AudioOutput::~MediaPlayer2AudioOutput() {
- for (auto routingDelegate : mRoutingDelegates) {
- JAudioTrack::removeGlobalRef(routingDelegate.second);
- }
close();
delete mCallbackData;
}
@@ -525,12 +522,18 @@
ALOGV("addAudioDeviceCallback");
Mutex::Autolock lock(mLock);
jobject listener = JAudioTrack::getListener(jRoutingDelegate);
- if (mJAudioTrack != nullptr &&
- JAudioTrack::findByKey(mRoutingDelegates, listener) == nullptr) {
+ if (JAudioTrack::findByKey(mRoutingDelegates, listener) == nullptr) {
+ sp<JObjectHolder> listenerHolder = new JObjectHolder(listener);
jobject handler = JAudioTrack::getHandler(jRoutingDelegate);
- jobject routingDelegate = JAudioTrack::addGlobalRef(jRoutingDelegate);
- mRoutingDelegates.push_back(std::pair<jobject, jobject>(listener, routingDelegate));
- return mJAudioTrack->addAudioDeviceCallback(routingDelegate, handler);
+ sp<JObjectHolder> routingDelegateHolder = new JObjectHolder(jRoutingDelegate);
+
+ mRoutingDelegates.push_back(std::pair<sp<JObjectHolder>, sp<JObjectHolder>>(
+ listenerHolder, routingDelegateHolder));
+
+ if (mJAudioTrack != nullptr) {
+ return mJAudioTrack->addAudioDeviceCallback(
+ routingDelegateHolder->getJObject(), handler);
+ }
}
return NO_ERROR;
}
@@ -539,13 +542,11 @@
ALOGV("removeAudioDeviceCallback");
Mutex::Autolock lock(mLock);
jobject routingDelegate = nullptr;
- if (mJAudioTrack != nullptr &&
- (routingDelegate = JAudioTrack::findByKey(mRoutingDelegates, listener)) != nullptr) {
- mJAudioTrack->removeAudioDeviceCallback(routingDelegate);
- JAudioTrack::eraseByKey(mRoutingDelegates, listener);
- if (JAudioTrack::removeGlobalRef(routingDelegate) != NO_ERROR) {
- return BAD_VALUE;
+ if ((routingDelegate = JAudioTrack::findByKey(mRoutingDelegates, listener)) != nullptr) {
+ if (mJAudioTrack != nullptr) {
+ mJAudioTrack->removeAudioDeviceCallback(routingDelegate);
}
+ JAudioTrack::eraseByKey(mRoutingDelegates, listener);
}
return NO_ERROR;
}
diff --git a/media/libmediaplayer2/include/mediaplayer2/JAudioTrack.h b/media/libmediaplayer2/include/mediaplayer2/JAudioTrack.h
index 87dc889..2ed4632 100644
--- a/media/libmediaplayer2/include/mediaplayer2/JAudioTrack.h
+++ b/media/libmediaplayer2/include/mediaplayer2/JAudioTrack.h
@@ -17,7 +17,6 @@
#ifndef ANDROID_JAUDIOTRACK_H
#define ANDROID_JAUDIOTRACK_H
-#include <vector>
#include <utility>
#include <jni.h>
#include <media/AudioResamplerPublic.h>
@@ -25,6 +24,7 @@
#include <media/VolumeShaper.h>
#include <system/audio.h>
#include <utils/Errors.h>
+#include <utils/Vector.h>
#include <mediaplayer2/JObjectHolder.h>
#include <media/AudioTimestamp.h> // It has dependency on audio.h/Errors.h, but doesn't
// include them in it. Therefore it is included here at last.
@@ -405,7 +405,8 @@
* routingDelegates: backed-up routing delegates
*
*/
- void registerRoutingDelegates(std::vector<std::pair<jobject, jobject>>& routingDelegates);
+ void registerRoutingDelegates(
+ Vector<std::pair<sp<JObjectHolder>, sp<JObjectHolder>>>& routingDelegates);
/* get listener from RoutingDelegate object
*/
@@ -415,17 +416,6 @@
*/
static jobject getHandler(const jobject routingDelegateObj);
- /* convert local reference to global reference.
- */
- static jobject addGlobalRef(const jobject obj);
-
- /* erase global reference.
- *
- * Returns NO_ERROR if succeeds
- * BAD_VALUE if obj is NULL
- */
- static status_t removeGlobalRef(const jobject obj);
-
/*
* Parameters:
* map and key
@@ -433,13 +423,15 @@
* Returns value if key is in the map
* nullptr if key is not in the map
*/
- static jobject findByKey(std::vector<std::pair<jobject, jobject>>& mp, const jobject key);
+ static jobject findByKey(
+ Vector<std::pair<sp<JObjectHolder>, sp<JObjectHolder>>>& mp, const jobject key);
/*
* Parameters:
* map and key
*/
- static void eraseByKey(std::vector<std::pair<jobject, jobject>>& mp, const jobject key);
+ static void eraseByKey(
+ Vector<std::pair<sp<JObjectHolder>, sp<JObjectHolder>>>& mp, const jobject key);
private:
audio_output_flags_t mFlags;
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
index bda4f61..f38b7cc 100644
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
+++ b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
@@ -22,7 +22,6 @@
#include <mediaplayer2/JAudioTrack.h>
#include <mediaplayer2/JObjectHolder.h>
-#include <vector>
#include <utility>
#include <utils/String16.h>
#include <utils/Vector.h>
@@ -125,7 +124,9 @@
audio_output_flags_t mFlags;
sp<JObjectHolder> mPreferredDevice;
mutable Mutex mLock;
- std::vector<std::pair<jobject, jobject>> mRoutingDelegates; // <listener, routingDelegate>
+
+ // <listener, routingDelegate>
+ Vector<std::pair<sp<JObjectHolder>, sp<JObjectHolder>>> mRoutingDelegates;
// static variables below not protected by mutex
static bool mIsOnEmulator;
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index 3fa8e3f..d6628d9 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -538,6 +538,22 @@
return NO_INIT;
}
+status_t MediaRecorderClient::setMicrophoneDirection(audio_microphone_direction_t direction) {
+ ALOGV("setMicrophoneDirection(%d)", direction);
+ if (mRecorder != NULL) {
+ return mRecorder->setMicrophoneDirection(direction);
+ }
+ return NO_INIT;
+}
+
+status_t MediaRecorderClient::setMicrophoneFieldDimension(float zoom) {
+ ALOGV("setMicrophoneFieldDimension(%f)", zoom);
+ if (mRecorder != NULL) {
+ return mRecorder->setMicrophoneFieldDimension(zoom);
+ }
+ return NO_INIT;
+}
+
status_t MediaRecorderClient::getPortId(audio_port_handle_t *portId) {
ALOGV("getPortId");
Mutex::Autolock lock(mLock);
diff --git a/media/libmediaplayerservice/MediaRecorderClient.h b/media/libmediaplayerservice/MediaRecorderClient.h
index 303cefc..8da718f 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.h
+++ b/media/libmediaplayerservice/MediaRecorderClient.h
@@ -109,6 +109,8 @@
virtual status_t enableAudioDeviceCallback(bool enabled);
virtual status_t getActiveMicrophones(
std::vector<media::MicrophoneInfo>* activeMicrophones);
+ virtual status_t setMicrophoneDirection(audio_microphone_direction_t direction);
+ virtual status_t setMicrophoneFieldDimension(float zoom);
status_t getPortId(audio_port_handle_t *portId) override;
private:
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index d111313..77777b8 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -118,7 +118,9 @@
mVideoSource(VIDEO_SOURCE_LIST_END),
mStarted(false),
mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
- mDeviceCallbackEnabled(false) {
+ mDeviceCallbackEnabled(false),
+ mSelectedMicDirection(MIC_DIRECTION_UNSPECIFIED),
+ mSelectedMicFieldDimension(MIC_FIELD_DIMENSION_NORMAL) {
ALOGV("Constructor");
@@ -398,14 +400,15 @@
return -EBADF;
}
- // start with a clean, empty file
- ftruncate(fd, 0);
- int nextFd = dup(fd);
- if (mWriter == NULL) {
+ if (mWriter == nullptr) {
ALOGE("setNextOutputFile failed. Writer has been freed");
return INVALID_OPERATION;
}
- return mWriter->setNextFd(nextFd);
+
+ // start with a clean, empty file
+ ftruncate(fd, 0);
+
+ return mWriter->setNextFd(fd);
}
// Attempt to parse an float literal optionally surrounded by whitespace,
@@ -1090,7 +1093,9 @@
mSampleRate,
mClientUid,
mClientPid,
- mSelectedDeviceId);
+ mSelectedDeviceId,
+ mSelectedMicDirection,
+ mSelectedMicFieldDimension);
status_t err = audioSource->initCheck();
@@ -2269,6 +2274,24 @@
return NO_INIT;
}
+status_t StagefrightRecorder::setMicrophoneDirection(audio_microphone_direction_t direction) {
+ ALOGV("setMicrophoneDirection(%d)", direction);
+ mSelectedMicDirection = direction;
+ if (mAudioSourceNode != 0) {
+ return mAudioSourceNode->setMicrophoneDirection(direction);
+ }
+ return NO_INIT;
+}
+
+status_t StagefrightRecorder::setMicrophoneFieldDimension(float zoom) {
+ ALOGV("setMicrophoneFieldDimension(%f)", zoom);
+ mSelectedMicFieldDimension = zoom;
+ if (mAudioSourceNode != 0) {
+ return mAudioSourceNode->setMicrophoneFieldDimension(zoom);
+ }
+ return NO_INIT;
+}
+
status_t StagefrightRecorder::getPortId(audio_port_handle_t *portId) const {
if (mAudioSourceNode != 0) {
return mAudioSourceNode->getPortId(portId);
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index a292e58..236b19e 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -77,6 +77,8 @@
virtual void setAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback>& callback);
virtual status_t enableAudioDeviceCallback(bool enabled);
virtual status_t getActiveMicrophones(std::vector<media::MicrophoneInfo>* activeMicrophones);
+ virtual status_t setMicrophoneDirection(audio_microphone_direction_t direction);
+ virtual status_t setMicrophoneFieldDimension(float zoom);
status_t getPortId(audio_port_handle_t *portId) const override;
private:
@@ -159,6 +161,9 @@
bool mDeviceCallbackEnabled;
wp<AudioSystem::AudioDeviceCallback> mAudioDeviceCallback;
+ audio_microphone_direction_t mSelectedMicDirection;
+ float mSelectedMicFieldDimension;
+
static const int kMaxHighSpeedFps = 1000;
status_t prepareInternal();
diff --git a/media/libstagefright/AACWriter.cpp b/media/libstagefright/AACWriter.cpp
index 9eba7e9..e173974 100644
--- a/media/libstagefright/AACWriter.cpp
+++ b/media/libstagefright/AACWriter.cpp
@@ -154,11 +154,11 @@
mDone = true;
void *dummy;
+ status_t status = mSource->stop();
pthread_join(mThread, &dummy);
status_t err = static_cast<status_t>(reinterpret_cast<uintptr_t>(dummy));
{
- status_t status = mSource->stop();
if (err == OK &&
(status != OK && status != ERROR_END_OF_STREAM)) {
err = status;
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 1dee4f7..f00c895 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -6667,7 +6667,7 @@
return false;
}
- mDeathNotifier = new DeathNotifier(notify);
+ mDeathNotifier = new DeathNotifier(new AMessage(kWhatOMXDied, mCodec));
auto tOmxNode = omxNode->getHalInterface<IOmxNode>();
if (tOmxNode && !tOmxNode->linkToDeath(mDeathNotifier, 0)) {
mDeathNotifier.clear();
diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp
index 41106a1..24f6f0b 100644
--- a/media/libstagefright/AMRWriter.cpp
+++ b/media/libstagefright/AMRWriter.cpp
@@ -149,11 +149,11 @@
mDone = true;
void *dummy;
+ status_t status = mSource->stop();
pthread_join(mThread, &dummy);
status_t err = static_cast<status_t>(reinterpret_cast<uintptr_t>(dummy));
{
- status_t status = mSource->stop();
if (err == OK &&
(status != OK && status != ERROR_END_OF_STREAM)) {
err = status;
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index d8b825d..dc51b16 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -225,6 +225,7 @@
],
export_shared_lib_headers: [
+ "libgui",
"libmedia",
"android.hidl.allocator@1.0",
],
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index 5027303..5f86bd3 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -52,7 +52,9 @@
AudioSource::AudioSource(
audio_source_t inputSource, const String16 &opPackageName,
uint32_t sampleRate, uint32_t channelCount, uint32_t outSampleRate,
- uid_t uid, pid_t pid, audio_port_handle_t selectedDeviceId)
+ uid_t uid, pid_t pid, audio_port_handle_t selectedDeviceId,
+ audio_microphone_direction_t selectedMicDirection,
+ float selectedMicFieldDimension)
: mStarted(false),
mSampleRate(sampleRate),
mOutSampleRate(outSampleRate > 0 ? outSampleRate : sampleRate),
@@ -103,7 +105,9 @@
uid,
pid,
NULL /*pAttributes*/,
- selectedDeviceId);
+ selectedDeviceId,
+ selectedMicDirection,
+ selectedMicFieldDimension);
mInitCheck = mRecord->initCheck();
if (mInitCheck != OK) {
mRecord.clear();
@@ -506,6 +510,22 @@
return NO_INIT;
}
+status_t AudioSource::setMicrophoneDirection(audio_microphone_direction_t direction) {
+ ALOGV("setMicrophoneDirection(%d)", direction);
+ if (mRecord != 0) {
+ return mRecord->setMicrophoneDirection(direction);
+ }
+ return NO_INIT;
+}
+
+status_t AudioSource::setMicrophoneFieldDimension(float zoom) {
+ ALOGV("setMicrophoneFieldDimension(%f)", zoom);
+ if (mRecord != 0) {
+ return mRecord->setMicrophoneFieldDimension(zoom);
+ }
+ return NO_INIT;
+}
+
status_t AudioSource::getPortId(audio_port_handle_t *portId) const {
if (mRecord != 0) {
*portId = mRecord->getPortId();
diff --git a/media/libstagefright/HevcUtils.cpp b/media/libstagefright/HevcUtils.cpp
index f152a38..482a1a7 100644
--- a/media/libstagefright/HevcUtils.cpp
+++ b/media/libstagefright/HevcUtils.cpp
@@ -312,14 +312,23 @@
for (uint32_t j = 0; j < numPics; ++j) {
skipUE(&reader); // delta_poc_s0|1_minus1[i]
reader.skipBits(1); // used_by_curr_pic_s0|1_flag[i]
+ if (reader.overRead()) {
+ return ERROR_MALFORMED;
+ }
}
}
+ if (reader.overRead()) {
+ return ERROR_MALFORMED;
+ }
}
if (reader.getBitsWithFallback(1, 0)) { // long_term_ref_pics_present_flag
uint32_t numLongTermRefPicSps = parseUEWithFallback(&reader, 0);
for (uint32_t i = 0; i < numLongTermRefPicSps; ++i) {
reader.skipBits(log2MaxPicOrderCntLsb); // lt_ref_pic_poc_lsb_sps[i]
reader.skipBits(1); // used_by_curr_pic_lt_sps_flag[i]
+ if (reader.overRead()) {
+ return ERROR_MALFORMED;
+ }
}
}
reader.skipBits(1); // sps_temporal_mvp_enabled_flag
@@ -457,8 +466,8 @@
if (numNalus == 0) {
continue;
}
- // array_completeness set to 0.
- header[0] = type;
+ // array_completeness set to 1.
+ header[0] = type | 0x80;
header[1] = (numNalus >> 8) & 0xff;
header[2] = numNalus & 0xff;
header += 3;
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 6259b15..a52da45 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -460,7 +460,7 @@
};
MPEG4Writer::MPEG4Writer(int fd) {
- initInternal(fd, true /*isFirstSession*/);
+ initInternal(dup(fd), true /*isFirstSession*/);
}
MPEG4Writer::~MPEG4Writer() {
@@ -481,7 +481,7 @@
void MPEG4Writer::initInternal(int fd, bool isFirstSession) {
ALOGV("initInternal");
- mFd = dup(fd);
+ mFd = fd;
mNextFd = -1;
mInitCheck = mFd < 0? NO_INIT: OK;
@@ -1044,6 +1044,10 @@
void MPEG4Writer::release() {
close(mFd);
mFd = -1;
+ if (mNextFd != -1) {
+ close(mNextFd);
+ mNextFd = -1;
+ }
mInitCheck = NO_INIT;
mStarted = false;
free(mInMemoryCache);
@@ -1981,7 +1985,7 @@
// No need to set a new FD yet.
return INVALID_OPERATION;
}
- mNextFd = fd;
+ mNextFd = dup(fd);
return OK;
}
@@ -2180,11 +2184,11 @@
switch (msg->what()) {
case kWhatSwitch:
{
- finishCurrentSession();
mLock.lock();
int fd = mNextFd;
mNextFd = -1;
mLock.unlock();
+ finishCurrentSession();
initInternal(fd, false /*isFirstSession*/);
start(mStartMeta.get());
mSwitchPending = false;
@@ -3128,8 +3132,8 @@
if (!mIsHeic) {
if (mStszTableEntries->count() == 0) {
mFirstSampleTimeRealUs = systemTime() / 1000;
+ mOwner->setStartTimestampUs(timestampUs);
mStartTimestampUs = timestampUs;
- mOwner->setStartTimestampUs(mStartTimestampUs);
previousPausedDurationUs = mStartTimestampUs;
}
diff --git a/media/libstagefright/OggWriter.cpp b/media/libstagefright/OggWriter.cpp
index 5c13983..cb87b55 100644
--- a/media/libstagefright/OggWriter.cpp
+++ b/media/libstagefright/OggWriter.cpp
@@ -295,6 +295,18 @@
mEstimatedSizeBytes, mMaxFileSizeLimitBytes);
break;
}
+
+ int32_t isCodecSpecific;
+ if ((buffer->meta_data().findInt32(kKeyIsCodecConfig, &isCodecSpecific)
+ && isCodecSpecific)
+ || IsOpusHeader((uint8_t*)buffer->data() + buffer->range_offset(),
+ buffer->range_length())) {
+ ALOGV("Drop codec specific info buffer");
+ buffer->release();
+ buffer = nullptr;
+ continue;
+ }
+
int64_t timestampUs;
CHECK(buffer->meta_data().findInt64(kKeyTime, ×tampUs));
if (timestampUs > mEstimatedDurationUs) {
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 16b3319..2aa9ed8 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -642,6 +642,15 @@
{ "icc-profile", kKeyIccProfile },
{ "sei", kKeySEI },
{ "text-format-data", kKeyTextFormatData },
+ { "thumbnail-csd-hevc", kKeyThumbnailHVCC },
+ }
+};
+
+static std::vector<std::pair<const char *, uint32_t>> CSDMappings {
+ {
+ { "csd-0", kKeyOpaqueCSD0 },
+ { "csd-1", kKeyOpaqueCSD1 },
+ { "csd-2", kKeyOpaqueCSD2 },
}
};
@@ -681,6 +690,14 @@
MetaDataBase::Type::TYPE_NONE, value->data(), value->size());
}
}
+
+ for (auto elem : CSDMappings) {
+ sp<ABuffer> value;
+ if (msg->findBuffer(elem.first, &value)) {
+ meta->setData(elem.second,
+ MetaDataBase::Type::TYPE_NONE, value->data(), value->size());
+ }
+ }
}
void convertMetaDataToMessageFromMappings(const MetaDataBase *meta, sp<AMessage> format) {
@@ -721,6 +738,18 @@
format->setBuffer(elem.first, buf);
}
}
+
+ for (auto elem : CSDMappings) {
+ uint32_t type;
+ const void* data;
+ size_t size;
+ if (meta->findData(elem.second, &type, &data, &size)) {
+ sp<ABuffer> buf = ABuffer::CreateAsCopy(data, size);
+ buf->meta()->setInt32("csd", true);
+ buf->meta()->setInt64("timeUs", 0);
+ format->setBuffer(elem.first, buf);
+ }
+ }
}
status_t convertMetaDataToMessage(
@@ -1248,30 +1277,6 @@
} else if (meta->findData(kKeyD263, &type, &data, &size)) {
const uint8_t *ptr = (const uint8_t *)data;
parseH263ProfileLevelFromD263(ptr, size, msg);
- } else if (meta->findData(kKeyVorbisInfo, &type, &data, &size)) {
- sp<ABuffer> buffer = new (std::nothrow) ABuffer(size);
- if (buffer.get() == NULL || buffer->base() == NULL) {
- return NO_MEMORY;
- }
- memcpy(buffer->data(), data, size);
-
- buffer->meta()->setInt32("csd", true);
- buffer->meta()->setInt64("timeUs", 0);
- msg->setBuffer("csd-0", buffer);
-
- if (!meta->findData(kKeyVorbisBooks, &type, &data, &size)) {
- return -EINVAL;
- }
-
- buffer = new (std::nothrow) ABuffer(size);
- if (buffer.get() == NULL || buffer->base() == NULL) {
- return NO_MEMORY;
- }
- memcpy(buffer->data(), data, size);
-
- buffer->meta()->setInt32("csd", true);
- buffer->meta()->setInt64("timeUs", 0);
- msg->setBuffer("csd-1", buffer);
} else if (meta->findData(kKeyOpusHeader, &type, &data, &size)) {
sp<ABuffer> buffer = new (std::nothrow) ABuffer(size);
if (buffer.get() == NULL || buffer->base() == NULL) {
@@ -1310,16 +1315,6 @@
buffer->meta()->setInt32("csd", true);
buffer->meta()->setInt64("timeUs", 0);
msg->setBuffer("csd-2", buffer);
- } else if (meta->findData(kKeyFlacMetadata, &type, &data, &size)) {
- sp<ABuffer> buffer = new (std::nothrow) ABuffer(size);
- if (buffer.get() == NULL || buffer->base() == NULL) {
- return NO_MEMORY;
- }
- memcpy(buffer->data(), data, size);
-
- buffer->meta()->setInt32("csd", true);
- buffer->meta()->setInt64("timeUs", 0);
- msg->setBuffer("csd-0", buffer);
} else if (meta->findData(kKeyVp9CodecPrivate, &type, &data, &size)) {
sp<ABuffer> buffer = new (std::nothrow) ABuffer(size);
if (buffer.get() == NULL || buffer->base() == NULL) {
@@ -1796,11 +1791,6 @@
if (seekPreRollBuf) {
meta->setData(kKeyOpusSeekPreRoll, 0, seekPreRollBuf, seekPreRollBufSize);
}
- } else if (mime == MEDIA_MIMETYPE_AUDIO_VORBIS) {
- meta->setData(kKeyVorbisInfo, 0, csd0->data(), csd0->size());
- if (msg->findBuffer("csd-1", &csd1)) {
- meta->setData(kKeyVorbisBooks, 0, csd1->data(), csd1->size());
- }
} else if (mime == MEDIA_MIMETYPE_AUDIO_ALAC) {
meta->setData(kKeyAlacMagicCookie, 0, csd0->data(), csd0->size());
}
diff --git a/media/libstagefright/VideoFrameScheduler2.cpp b/media/libstagefright/VideoFrameScheduler2.cpp
index fc76904..23671f2 100644
--- a/media/libstagefright/VideoFrameScheduler2.cpp
+++ b/media/libstagefright/VideoFrameScheduler2.cpp
@@ -160,13 +160,13 @@
mPhase = (long) (atan2(sampleAvgY, sampleAvgX) / scale);
}
-static void frameCallback(long frameTimeNanos, void* data) {
+static void frameCallback(int64_t frameTimeNanos, void* data) {
if (data == NULL) {
return;
}
sp<VsyncTracker> vsyncTracker(static_cast<VsyncTracker*>(data));
vsyncTracker->addSample(frameTimeNanos);
- AChoreographer_postFrameCallback(AChoreographer_getInstance(),
+ AChoreographer_postFrameCallback64(AChoreographer_getInstance(),
frameCallback, static_cast<void*>(vsyncTracker.get()));
}
@@ -247,7 +247,7 @@
if (AChoreographer_getInstance() == NULL) {
return NO_INIT;
}
- AChoreographer_postFrameCallback(AChoreographer_getInstance(), frameCallback, mData);
+ AChoreographer_postFrameCallback64(AChoreographer_getInstance(), frameCallback, mData);
return OK;
}
diff --git a/media/libstagefright/codecs/m4v_h263/enc/test/m4v_h263_enc_test.cpp b/media/libstagefright/codecs/m4v_h263/enc/test/m4v_h263_enc_test.cpp
index db2c61a..5554ebd 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/test/m4v_h263_enc_test.cpp
+++ b/media/libstagefright/codecs/m4v_h263/enc/test/m4v_h263_enc_test.cpp
@@ -183,6 +183,10 @@
// Initialize the encoder.
if (!PVInitVideoEncoder(&handle, &encParams)) {
fprintf(stderr, "Failed to initialize the encoder\n");
+ fclose(fpInput);
+ fclose(fpOutput);
+ free(inputBuf);
+ free(outputBuf);
return EXIT_FAILURE;
}
@@ -190,6 +194,10 @@
int32_t headerLength = kOutputBufferSize;
if (!PVGetVolHeader(&handle, outputBuf, &headerLength, 0)) {
fprintf(stderr, "Failed to get VOL header\n");
+ fclose(fpInput);
+ fclose(fpOutput);
+ free(inputBuf);
+ free(outputBuf);
return EXIT_FAILURE;
}
fwrite(outputBuf, 1, headerLength, fpOutput);
diff --git a/media/libstagefright/foundation/MediaDefs.cpp b/media/libstagefright/foundation/MediaDefs.cpp
index 9d1ec1f..52b2765 100644
--- a/media/libstagefright/foundation/MediaDefs.cpp
+++ b/media/libstagefright/foundation/MediaDefs.cpp
@@ -32,6 +32,10 @@
const char *MEDIA_MIMETYPE_VIDEO_RAW = "video/raw";
const char *MEDIA_MIMETYPE_VIDEO_DOLBY_VISION = "video/dolby-vision";
const char *MEDIA_MIMETYPE_VIDEO_SCRAMBLED = "video/scrambled";
+const char *MEDIA_MIMETYPE_VIDEO_DIVX = "video/divx";
+const char *MEDIA_MIMETYPE_VIDEO_DIVX3 = "video/divx3";
+const char *MEDIA_MIMETYPE_VIDEO_XVID = "video/xvid";
+const char *MEDIA_MIMETYPE_VIDEO_MJPEG = "video/x-motion-jpeg";
const char *MEDIA_MIMETYPE_AUDIO_AMR_NB = "audio/3gpp";
const char *MEDIA_MIMETYPE_AUDIO_AMR_WB = "audio/amr-wb";
diff --git a/media/libstagefright/foundation/OpusHeader.cpp b/media/libstagefright/foundation/OpusHeader.cpp
index 9faede1..acb9ccf 100644
--- a/media/libstagefright/foundation/OpusHeader.cpp
+++ b/media/libstagefright/foundation/OpusHeader.cpp
@@ -15,9 +15,9 @@
*/
//#define LOG_NDEBUG 0
-#define LOG_TAG "SoftOpus"
-#include <algorithm>
+#define LOG_TAG "OpusHeader"
#include <cstring>
+#include <inttypes.h>
#include <stdint.h>
#include <log/log.h>
@@ -91,6 +91,9 @@
// Parses Opus Header. Header spec: http://wiki.xiph.org/OggOpus#ID_Header
bool ParseOpusHeader(const uint8_t* data, size_t data_size, OpusHeader* header) {
+ if (data == NULL) {
+ return false;
+ }
if (data_size < kOpusHeaderSize) {
ALOGV("Header size is too small.");
return false;
@@ -183,53 +186,88 @@
ALOGD("Buffer not large enough to hold unified OPUS CSD");
return -1;
}
+ int headerLen = 0;
- int headerLen = WriteOpusHeader(header, inputSampleRate, output,
+ // Add opus header
+ /*
+ Following is the CSD syntax for signalling OpusHeader
+ (http://wiki.xiph.org/OggOpus#ID_Header)
+
+ Marker (8 bytes) | Length (8 bytes) | OpusHeader
+
+ Markers supported:
+ AOPUS_CSD_OPUS_HEADER_MARKER - Signals Opus Header
+
+ Length should be a value within AOPUS_OPUSHEAD_MINSIZE and AOPUS_OPUSHEAD_MAXSIZE.
+ */
+
+ memcpy(output + headerLen, AOPUS_CSD_OPUS_HEADER_MARKER, AOPUS_MARKER_SIZE);
+ headerLen += AOPUS_MARKER_SIZE;
+
+ // Place holder for opusHeader Size
+ headerLen += AOPUS_LENGTH_SIZE;
+
+ int headerSize = WriteOpusHeader(header, inputSampleRate, output + headerLen,
outputSize);
- if (headerLen < 0) {
- ALOGD("WriteOpusHeader failed");
+ if (headerSize < 0) {
+ ALOGD("%s: WriteOpusHeader failed", __func__);
return -1;
}
- if (headerLen >= (outputSize - 2 * AOPUS_TOTAL_CSD_SIZE)) {
- ALOGD("Buffer not large enough to hold codec delay and seek pre roll");
- return -1;
- }
+ headerLen += headerSize;
- uint64_t length = AOPUS_LENGTH;
+ // Update opus headerSize after AOPUS_CSD_OPUS_HEADER_MARKER
+ uint64_t length = headerSize;
+ memcpy(output + AOPUS_MARKER_SIZE, &length, AOPUS_LENGTH_SIZE);
/*
Following is the CSD syntax for signalling codec delay and
seek pre-roll which is to be appended after OpusHeader
- Marker (8 bytes) | Length (8 bytes) | Samples (8 bytes)
+ Marker (8 bytes) | Length (8 bytes) | Samples in ns (8 bytes)
Markers supported:
- AOPUSDLY - Signals Codec Delay
- AOPUSPRL - Signals seek pre roll
+ AOPUS_CSD_CODEC_DELAY_MARKER - codec delay as samples in ns, represented in 8 bytes
+ AOPUS_CSD_SEEK_PREROLL_MARKER - preroll adjustment as samples in ns, represented in 8 bytes
- Length should be 8.
*/
-
+ length = sizeof(codecDelay);
+ if (headerLen > (outputSize - AOPUS_MARKER_SIZE - AOPUS_LENGTH_SIZE - length)) {
+ ALOGD("Buffer not large enough to hold codec delay");
+ return -1;
+ }
// Add codec delay
memcpy(output + headerLen, AOPUS_CSD_CODEC_DELAY_MARKER, AOPUS_MARKER_SIZE);
headerLen += AOPUS_MARKER_SIZE;
memcpy(output + headerLen, &length, AOPUS_LENGTH_SIZE);
headerLen += AOPUS_LENGTH_SIZE;
- memcpy(output + headerLen, &codecDelay, AOPUS_CSD_SIZE);
- headerLen += AOPUS_CSD_SIZE;
+ memcpy(output + headerLen, &codecDelay, length);
+ headerLen += length;
+ length = sizeof(seekPreRoll);
+ if (headerLen > (outputSize - AOPUS_MARKER_SIZE - AOPUS_LENGTH_SIZE - length)) {
+ ALOGD("Buffer not large enough to hold seek pre roll");
+ return -1;
+ }
// Add skip pre roll
memcpy(output + headerLen, AOPUS_CSD_SEEK_PREROLL_MARKER, AOPUS_MARKER_SIZE);
headerLen += AOPUS_MARKER_SIZE;
memcpy(output + headerLen, &length, AOPUS_LENGTH_SIZE);
headerLen += AOPUS_LENGTH_SIZE;
- memcpy(output + headerLen, &seekPreRoll, AOPUS_CSD_SIZE);
- headerLen += AOPUS_CSD_SIZE;
+ memcpy(output + headerLen, &seekPreRoll, length);
+ headerLen += length;
return headerLen;
}
-void GetOpusHeaderBuffers(const uint8_t *data, size_t data_size,
+bool IsOpusHeader(const uint8_t *data, size_t data_size) {
+ if (data_size < AOPUS_MARKER_SIZE) {
+ return false;
+ }
+
+ return !memcmp(data, AOPUS_CSD_OPUS_HEADER_MARKER, AOPUS_MARKER_SIZE);
+}
+
+bool GetOpusHeaderBuffers(const uint8_t *data, size_t data_size,
void **opusHeadBuf, size_t *opusHeadSize,
void **codecDelayBuf, size_t *codecDelaySize,
void **seekPreRollBuf, size_t *seekPreRollSize) {
@@ -237,26 +275,77 @@
*codecDelaySize = 0;
*seekPreRollBuf = NULL;
*seekPreRollSize = 0;
- *opusHeadBuf = (void *)data;
- *opusHeadSize = data_size;
- if (data_size >= AOPUS_UNIFIED_CSD_MINSIZE) {
+ *opusHeadBuf = NULL;
+ *opusHeadSize = 0;
+
+ // AOPUS_MARKER_SIZE is 8 "OpusHead" is of size 8
+ if (data_size < 8)
+ return false;
+
+ // Check if the CSD is in legacy format
+ if (!memcmp("OpusHead", data, 8)) {
+ if (data_size < AOPUS_OPUSHEAD_MINSIZE || data_size > AOPUS_OPUSHEAD_MAXSIZE) {
+ ALOGD("Unexpected size for opusHeadSize %zu", data_size);
+ return false;
+ }
+ *opusHeadBuf = (void *)data;
+ *opusHeadSize = data_size;
+ return true;
+ } else if (memcmp(AOPUS_CSD_MARKER_PREFIX, data, AOPUS_CSD_MARKER_PREFIX_SIZE) == 0) {
size_t i = 0;
- while (i < data_size - AOPUS_TOTAL_CSD_SIZE) {
+ bool found = false;
+ while (i <= data_size - AOPUS_MARKER_SIZE - AOPUS_LENGTH_SIZE) {
uint8_t *csdBuf = (uint8_t *)data + i;
- if (!memcmp(csdBuf, AOPUS_CSD_CODEC_DELAY_MARKER, AOPUS_MARKER_SIZE)) {
- *opusHeadSize = std::min(*opusHeadSize, i);
+ if (!memcmp(csdBuf, AOPUS_CSD_OPUS_HEADER_MARKER, AOPUS_MARKER_SIZE)) {
+ uint64_t value;
+ memcpy(&value, csdBuf + AOPUS_MARKER_SIZE, sizeof(value));
+ if (value < AOPUS_OPUSHEAD_MINSIZE || value > AOPUS_OPUSHEAD_MAXSIZE) {
+ ALOGD("Unexpected size for opusHeadSize %" PRIu64, value);
+ return false;
+ }
+ i += AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE + value;
+ if (i > data_size) {
+ ALOGD("Marker signals a header that is larger than input");
+ return false;
+ }
+ *opusHeadBuf = csdBuf + AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE;
+ *opusHeadSize = value;
+ found = true;
+ } else if (!memcmp(csdBuf, AOPUS_CSD_CODEC_DELAY_MARKER, AOPUS_MARKER_SIZE)) {
+ uint64_t value;
+ memcpy(&value, csdBuf + AOPUS_MARKER_SIZE, sizeof(value));
+ if (value != sizeof(uint64_t)) {
+ ALOGD("Unexpected size for codecDelay %" PRIu64, value);
+ return false;
+ }
+ i += AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE + value;
+ if (i > data_size) {
+ ALOGD("Marker signals a header that is larger than input");
+ return false;
+ }
*codecDelayBuf = csdBuf + AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE;
- *codecDelaySize = AOPUS_CSD_SIZE;
- i += AOPUS_TOTAL_CSD_SIZE;
+ *codecDelaySize = value;
} else if (!memcmp(csdBuf, AOPUS_CSD_SEEK_PREROLL_MARKER, AOPUS_MARKER_SIZE)) {
- *opusHeadSize = std::min(*opusHeadSize, i);
+ uint64_t value;
+ memcpy(&value, csdBuf + AOPUS_MARKER_SIZE, sizeof(value));
+ if (value != sizeof(uint64_t)) {
+ ALOGD("Unexpected size for seekPreRollSize %" PRIu64, value);
+ return false;
+ }
+ i += AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE + value;
+ if (i > data_size) {
+ ALOGD("Marker signals a header that is larger than input");
+ return false;
+ }
*seekPreRollBuf = csdBuf + AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE;
- *seekPreRollSize = AOPUS_CSD_SIZE;
- i += AOPUS_TOTAL_CSD_SIZE;
+ *seekPreRollSize = value;
} else {
i++;
}
}
+ return found;
+ } else {
+ return false; // it isn't in either format
}
}
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h b/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
index e68852d..007a09b 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
@@ -34,6 +34,10 @@
extern const char *MEDIA_MIMETYPE_VIDEO_RAW;
extern const char *MEDIA_MIMETYPE_VIDEO_DOLBY_VISION;
extern const char *MEDIA_MIMETYPE_VIDEO_SCRAMBLED;
+extern const char *MEDIA_MIMETYPE_VIDEO_DIVX;
+extern const char *MEDIA_MIMETYPE_VIDEO_DIVX3;
+extern const char *MEDIA_MIMETYPE_VIDEO_XVID;
+extern const char *MEDIA_MIMETYPE_VIDEO_MJPEG;
extern const char *MEDIA_MIMETYPE_AUDIO_AMR_NB;
extern const char *MEDIA_MIMETYPE_AUDIO_AMR_WB;
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/OpusHeader.h b/media/libstagefright/foundation/include/media/stagefright/foundation/OpusHeader.h
index 9bffccb..29037af 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/OpusHeader.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/OpusHeader.h
@@ -25,22 +25,37 @@
namespace android {
/* Constants used for delimiting Opus CSD */
-#define AOPUS_CSD_CODEC_DELAY_MARKER "AOPUSDLY"
-#define AOPUS_CSD_SEEK_PREROLL_MARKER "AOPUSPRL"
-#define AOPUS_CSD_SIZE 8
-#define AOPUS_LENGTH 8
+#define AOPUS_CSD_MARKER_PREFIX "AOPUS"
+#define AOPUS_CSD_MARKER_PREFIX_SIZE (sizeof(AOPUS_CSD_MARKER_PREFIX) - 1)
+#define AOPUS_CSD_OPUS_HEADER_MARKER AOPUS_CSD_MARKER_PREFIX "HDR"
+#define AOPUS_CSD_CODEC_DELAY_MARKER AOPUS_CSD_MARKER_PREFIX "DLY"
+#define AOPUS_CSD_SEEK_PREROLL_MARKER AOPUS_CSD_MARKER_PREFIX "PRL"
#define AOPUS_MARKER_SIZE 8
-#define AOPUS_LENGTH_SIZE 8
-#define AOPUS_TOTAL_CSD_SIZE \
- ((AOPUS_MARKER_SIZE) + (AOPUS_LENGTH_SIZE) + (AOPUS_CSD_SIZE))
-#define AOPUS_CSD0_MINSIZE 19
-#define AOPUS_UNIFIED_CSD_MINSIZE \
- ((AOPUS_CSD0_MINSIZE) + 2 * (AOPUS_TOTAL_CSD_SIZE))
+#define AOPUS_LENGTH_SIZE sizeof(uint64_t)
+#define AOPUS_CSD_CODEC_DELAY_SIZE \
+ (AOPUS_MARKER_SIZE) + (AOPUS_LENGTH_SIZE) + sizeof(uint64_t)
+#define AOPUS_CSD_SEEK_PREROLL_SIZE \
+ (AOPUS_MARKER_SIZE) + (AOPUS_LENGTH_SIZE) + sizeof(uint64_t)
-/* CSD0 at max can be 22 bytes + max number of channels (255) */
-#define AOPUS_CSD0_MAXSIZE 277
+/* OpusHead csd minimum size is 19 */
+#define AOPUS_OPUSHEAD_MINSIZE 19
+#define AOPUS_CSD_OPUSHEAD_MINSIZE \
+ (AOPUS_MARKER_SIZE) + (AOPUS_LENGTH_SIZE) + (AOPUS_OPUSHEAD_MINSIZE)
+
+#define AOPUS_UNIFIED_CSD_MINSIZE \
+ ((AOPUS_CSD_OPUSHEAD_MINSIZE) + \
+ (AOPUS_CSD_CODEC_DELAY_SIZE) + \
+ (AOPUS_CSD_SEEK_PREROLL_SIZE))
+
+/* OpusHead csd at max can be AOPUS_CSD_OPUSHEAD_MINSIZE + 2 + max number of channels (255) */
+#define AOPUS_OPUSHEAD_MAXSIZE ((AOPUS_OPUSHEAD_MINSIZE) + 2 + 255)
+#define AOPUS_CSD_OPUSHEAD_MAXSIZE \
+ (AOPUS_MARKER_SIZE) + (AOPUS_LENGTH_SIZE) + (AOPUS_OPUSHEAD_MAXSIZE)
+
#define AOPUS_UNIFIED_CSD_MAXSIZE \
- ((AOPUS_CSD0_MAXSIZE) + 2 * (AOPUS_TOTAL_CSD_SIZE))
+ ((AOPUS_CSD_OPUSHEAD_MAXSIZE) + \
+ (AOPUS_CSD_CODEC_DELAY_SIZE) + \
+ (AOPUS_CSD_SEEK_PREROLL_SIZE))
struct OpusHeader {
int channels;
@@ -54,13 +69,14 @@
bool ParseOpusHeader(const uint8_t* data, size_t data_size, OpusHeader* header);
int WriteOpusHeader(const OpusHeader &header, int input_sample_rate, uint8_t* output, size_t output_size);
-void GetOpusHeaderBuffers(const uint8_t *data, size_t data_size,
+bool GetOpusHeaderBuffers(const uint8_t *data, size_t data_size,
void **opusHeadBuf, size_t *opusHeadSize,
void **codecDelayBuf, size_t *codecDelaySize,
void **seekPreRollBuf, size_t *seekPreRollSize);
int WriteOpusHeaders(const OpusHeader &header, int inputSampleRate,
uint8_t* output, size_t outputSize, uint64_t codecDelay,
uint64_t seekPreRoll);
+bool IsOpusHeader(const uint8_t *data, size_t data_size);
} // namespace android
#endif // OPUS_HEADER_H_
diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp
index b2361b8..cb97a3c 100644
--- a/media/libstagefright/httplive/M3UParser.cpp
+++ b/media/libstagefright/httplive/M3UParser.cpp
@@ -1397,6 +1397,18 @@
case 'ulaw':
case 'vdva':
case 'ac-4':
+ case 'Opus':
+ case 'a3ds':
+ case 'dts+':
+ case 'dts-':
+ case 'dtsx':
+ case 'dtsy':
+ case 'ec+3':
+ case 'mha1':
+ case 'mha2':
+ case 'mhm1':
+ case 'mhm2':
+ case 'sevs':
return !strcmp("audio", type);
case 'avc1':
@@ -1445,6 +1457,35 @@
case 'tga ':
case 'tiff':
case 'WRLE':
+ case 'a3d1':
+ case 'a3d2':
+ case 'a3d3':
+ case 'a3d4':
+ case 'avc3':
+ case 'avc4':
+ case 'dva1':
+ case 'dvav':
+ case 'dvh1':
+ case 'dvhe':
+ case 'hev1':
+ case 'hev2':
+ case 'hvc1':
+ case 'hvc2':
+ case 'hvt1':
+ case 'lhe1':
+ case 'lht1':
+ case 'lhv1':
+ case 'mjpg':
+ case 'mvc3':
+ case 'mvc4':
+ case 'mvd1':
+ case 'mvd2':
+ case 'mvd3':
+ case 'mvd4':
+ case 'rv60':
+ case 'svc2':
+ case 'vp08':
+ case 'vp09':
return !strcmp("video", type);
default:
diff --git a/media/libstagefright/include/media/stagefright/AudioSource.h b/media/libstagefright/include/media/stagefright/AudioSource.h
index b0e32d0..18e5f10 100644
--- a/media/libstagefright/include/media/stagefright/AudioSource.h
+++ b/media/libstagefright/include/media/stagefright/AudioSource.h
@@ -44,7 +44,9 @@
uint32_t outSampleRate = 0,
uid_t uid = -1,
pid_t pid = -1,
- audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE);
+ audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE,
+ audio_microphone_direction_t selectedMicDirection = MIC_DIRECTION_UNSPECIFIED,
+ float selectedMicFieldDimension = MIC_FIELD_DIMENSION_NORMAL);
status_t initCheck() const;
@@ -68,6 +70,8 @@
status_t removeAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback>& callback);
status_t getActiveMicrophones(std::vector<media::MicrophoneInfo>* activeMicrophones);
+ status_t setMicrophoneDirection(audio_microphone_direction_t direction);
+ status_t setMicrophoneFieldDimension(float zoom);
status_t getPortId(audio_port_handle_t *portId) const;
diff --git a/media/libstagefright/include/media/stagefright/MetaDataBase.h b/media/libstagefright/include/media/stagefright/MetaDataBase.h
index a0407af..75fd0d9 100644
--- a/media/libstagefright/include/media/stagefright/MetaDataBase.h
+++ b/media/libstagefright/include/media/stagefright/MetaDataBase.h
@@ -67,7 +67,6 @@
kKeyOpusHeader = 'ohdr', // raw data
kKeyOpusCodecDelay = 'ocod', // uint64_t (codec delay in ns)
kKeyOpusSeekPreRoll = 'ospr', // uint64_t (seek preroll in ns)
- kKeyFlacMetadata = 'flMd', // raw data
kKeyVp9CodecPrivate = 'vp9p', // raw data (vp9 csd information)
kKeyIsSyncFrame = 'sync', // int32_t (bool)
kKeyIsCodecConfig = 'conf', // int32_t (bool)
@@ -234,6 +233,11 @@
// AC-4 AudioPresentationInfo
kKeyAudioPresentationInfo = 'audP', // raw data
+
+ // opaque codec specific data being passed from extractor to codec
+ kKeyOpaqueCSD0 = 'csd0',
+ kKeyOpaqueCSD1 = 'csd1',
+ kKeyOpaqueCSD2 = 'csd2',
};
enum {
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index b91edcd..5af7b23 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -1526,6 +1526,7 @@
header, &frameSize, &samplingRate, &numChannels,
&bitrate, &numSamples)) {
ALOGE("Failed to get audio frame size");
+ mBuffer->setRange(0, 0);
return NULL;
}
@@ -1550,6 +1551,22 @@
return NULL;
}
+ if (mFormat != NULL) {
+ const char *mime;
+ if (mFormat->findCString(kKeyMIMEType, &mime)) {
+ if ((layer == 1) && strcmp (mime, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I)) {
+ ALOGE("Audio layer is not MPEG_LAYER_I");
+ return NULL;
+ } else if ((layer == 2) && strcmp (mime, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II)) {
+ ALOGE("Audio layer is not MPEG_LAYER_II");
+ return NULL;
+ } else if ((layer == 3) && strcmp (mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
+ ALOGE("Audio layer is not AUDIO_MPEG");
+ return NULL;
+ }
+ }
+ }
+
accessUnit->meta()->setInt64("timeUs", timeUs);
accessUnit->meta()->setInt32("isSync", 1);
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index b964bc0..1aa8a20 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -376,8 +376,8 @@
ALOGI("VOL dimensions = %dx%d", *width, *height);
size_t len1 = config->size() + GetSizeWidth(config->size()) + 1;
- size_t len2 = len1 + GetSizeWidth(len1) + 1 + 13;
- size_t len3 = len2 + GetSizeWidth(len2) + 1 + 3;
+ size_t len2 = len1 + GetSizeWidth(len1 + 13) + 1 + 13;
+ size_t len3 = len2 + GetSizeWidth(len2 + 3) + 1 + 3;
sp<ABuffer> csd = new ABuffer(len3);
uint8_t *dst = csd->data();
diff --git a/media/libstagefright/xmlparser/Android.bp b/media/libstagefright/xmlparser/Android.bp
index 819058c..202e964 100644
--- a/media/libstagefright/xmlparser/Android.bp
+++ b/media/libstagefright/xmlparser/Android.bp
@@ -10,7 +10,6 @@
vndk: {
enabled: true,
},
- double_loadable: true,
srcs: [
"MediaCodecsXmlParser.cpp",
@@ -47,3 +46,9 @@
}
+xsd_config {
+ name: "media_codecs",
+ srcs: ["media_codecs.xsd"],
+ package_name: "media.codecs",
+}
+
diff --git a/media/libstagefright/xmlparser/api/current.txt b/media/libstagefright/xmlparser/api/current.txt
new file mode 100644
index 0000000..f5245c1
--- /dev/null
+++ b/media/libstagefright/xmlparser/api/current.txt
@@ -0,0 +1,108 @@
+// Signature format: 2.0
+package media.codecs {
+
+ public class Decoders {
+ ctor public Decoders();
+ method public java.util.List<media.codecs.MediaCodec> getMediaCodec();
+ }
+
+ public class Encoders {
+ ctor public Encoders();
+ method public java.util.List<media.codecs.MediaCodec> getMediaCodec();
+ }
+
+ public class Feature {
+ ctor public Feature();
+ method public String getName();
+ method public String getOptional();
+ method public String getRequired();
+ method public String getValue();
+ method public void setName(String);
+ method public void setOptional(String);
+ method public void setRequired(String);
+ method public void setValue(String);
+ }
+
+ public class Limit {
+ ctor public Limit();
+ method public String getIn();
+ method public String getMax();
+ method public String getMin();
+ method public String getName();
+ method public String getRange();
+ method public String getRanges();
+ method public String getScale();
+ method public String getValue();
+ method public String get_default();
+ method public void setIn(String);
+ method public void setMax(String);
+ method public void setMin(String);
+ method public void setName(String);
+ method public void setRange(String);
+ method public void setRanges(String);
+ method public void setScale(String);
+ method public void setValue(String);
+ method public void set_default(String);
+ }
+
+ public class MediaCodec {
+ ctor public MediaCodec();
+ method public java.util.List<media.codecs.Feature> getFeature();
+ method public java.util.List<media.codecs.Limit> getLimit();
+ method public String getName();
+ method public java.util.List<media.codecs.Quirk> getQuirk();
+ method public java.util.List<media.codecs.Type> getType();
+ method public String getType();
+ method public String getUpdate();
+ method public void setName(String);
+ method public void setType(String);
+ method public void setUpdate(String);
+ }
+
+ public class MediaCodecs {
+ ctor public MediaCodecs();
+ method public java.util.List<media.codecs.Decoders> getDecoders();
+ method public java.util.List<media.codecs.Encoders> getEncoders();
+ method public java.util.List<media.codecs.Settings> getSettings();
+ }
+
+ public class Quirk {
+ ctor public Quirk();
+ method public String getName();
+ method public void setName(String);
+ }
+
+ public class Setting {
+ ctor public Setting();
+ method public String getName();
+ method public String getUpdate();
+ method public String getValue();
+ method public void setName(String);
+ method public void setUpdate(String);
+ method public void setValue(String);
+ }
+
+ public class Settings {
+ ctor public Settings();
+ method public java.util.List<media.codecs.Setting> getSetting();
+ }
+
+ public class Type {
+ ctor public Type();
+ method public java.util.List<media.codecs.Feature> getFeature();
+ method public java.util.List<media.codecs.Limit> getLimit();
+ method public String getName();
+ method public String getUpdate();
+ method public void setName(String);
+ method public void setUpdate(String);
+ }
+
+ public class XmlParser {
+ ctor public XmlParser();
+ method public static media.codecs.MediaCodecs read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ }
+
+}
+
diff --git a/media/libstagefright/xmlparser/api/last_current.txt b/media/libstagefright/xmlparser/api/last_current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/media/libstagefright/xmlparser/api/last_current.txt
diff --git a/media/libstagefright/xmlparser/api/last_removed.txt b/media/libstagefright/xmlparser/api/last_removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/media/libstagefright/xmlparser/api/last_removed.txt
diff --git a/media/libstagefright/xmlparser/api/removed.txt b/media/libstagefright/xmlparser/api/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/media/libstagefright/xmlparser/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/media/libstagefright/xmlparser/media_codecs.xsd b/media/libstagefright/xmlparser/media_codecs.xsd
new file mode 100644
index 0000000..4faba87
--- /dev/null
+++ b/media/libstagefright/xmlparser/media_codecs.xsd
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+<!-- TODO: define a targetNamespace. Note that it will break retrocompatibility -->
+<xs:schema version="2.0"
+ elementFormDefault="qualified"
+ attributeFormDefault="unqualified"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <xs:element name="MediaCodecs">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="Decoders" type="Decoders" maxOccurs="unbounded"/>
+ <xs:element name="Encoders" type="Encoders" maxOccurs="unbounded"/>
+ <xs:element name="Settings" type="Settings" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:complexType name="Decoders">
+ <xs:sequence>
+ <xs:element name="MediaCodec" type="MediaCodec" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="Encoders">
+ <xs:sequence>
+ <xs:element name="MediaCodec" type="MediaCodec" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="Settings">
+ <xs:sequence>
+ <xs:element name="Setting" type="Setting" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="MediaCodec">
+ <xs:sequence>
+ <xs:element name="Quirk" type="Quirk" maxOccurs="unbounded"/>
+ <xs:element name="Type" type="Type" maxOccurs="unbounded"/>
+ <xs:element name="Limit" type="Limit" maxOccurs="unbounded"/>
+ <xs:element name="Feature" type="Feature" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:string"/>
+ <xs:attribute name="type" type="xs:string"/>
+ <xs:attribute name="update" type="xs:string"/>
+ </xs:complexType>
+ <xs:complexType name="Quirk">
+ <xs:attribute name="name" type="xs:string"/>
+ </xs:complexType>
+ <xs:complexType name="Type">
+ <xs:sequence>
+ <xs:element name="Limit" type="Limit" maxOccurs="unbounded"/>
+ <xs:element name="Feature" type="Feature" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:string"/>
+ <xs:attribute name="update" type="xs:string"/>
+ </xs:complexType>
+ <xs:complexType name="Limit">
+ <xs:attribute name="name" type="xs:string"/>
+ <xs:attribute name="default" type="xs:string"/>
+ <xs:attribute name="in" type="xs:string"/>
+ <xs:attribute name="max" type="xs:string"/>
+ <xs:attribute name="min" type="xs:string"/>
+ <xs:attribute name="range" type="xs:string"/>
+ <xs:attribute name="ranges" type="xs:string"/>
+ <xs:attribute name="scale" type="xs:string"/>
+ <xs:attribute name="value" type="xs:string"/>
+ </xs:complexType>
+ <xs:complexType name="Feature">
+ <xs:attribute name="name" type="xs:string"/>
+ <xs:attribute name="optional" type="xs:string"/>
+ <xs:attribute name="required" type="xs:string"/>
+ <xs:attribute name="value" type="xs:string"/>
+ </xs:complexType>
+ <xs:complexType name="Setting">
+ <xs:attribute name="name" type="xs:string"/>
+ <xs:attribute name="value" type="xs:string"/>
+ <xs:attribute name="update" type="xs:string"/>
+ </xs:complexType>
+</xs:schema>
diff --git a/media/mediaserver/Android.bp b/media/mediaserver/Android.bp
index 8377723..6a1cc71 100644
--- a/media/mediaserver/Android.bp
+++ b/media/mediaserver/Android.bp
@@ -25,7 +25,6 @@
],
static_libs: [
- "libicuandroid_utils",
"libregistermsext",
],
diff --git a/media/mediaserver/main_mediaserver.cpp b/media/mediaserver/main_mediaserver.cpp
index ecddc48..7b22b05 100644
--- a/media/mediaserver/main_mediaserver.cpp
+++ b/media/mediaserver/main_mediaserver.cpp
@@ -18,6 +18,7 @@
#define LOG_TAG "mediaserver"
//#define LOG_NDEBUG 0
+#include <aicu/AIcu.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
@@ -25,7 +26,6 @@
#include "RegisterExtensions.h"
// from LOCAL_C_INCLUDES
-#include "IcuUtils.h"
#include "MediaPlayerService.h"
#include "ResourceManagerService.h"
@@ -38,7 +38,7 @@
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm(defaultServiceManager());
ALOGI("ServiceManager: %p", sm.get());
- InitializeIcuOrDie();
+ AIcu_initializeIcuOrDie();
MediaPlayerService::instantiate();
ResourceManagerService::instantiate();
registerExtensions();
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index f9f1acc..f4cc704 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -101,6 +101,10 @@
export_include_dirs: ["include"],
+ export_shared_lib_headers: [
+ "libgui",
+ ],
+
product_variables: {
pdk: {
enabled: false,
diff --git a/media/ndk/NdkImageReader.cpp b/media/ndk/NdkImageReader.cpp
index bcc7ff3..22e15d3 100644
--- a/media/ndk/NdkImageReader.cpp
+++ b/media/ndk/NdkImageReader.cpp
@@ -21,6 +21,7 @@
#include "NdkImagePriv.h"
#include "NdkImageReaderPriv.h"
+#include <private/media/NdkImage.h>
#include <cutils/atomic.h>
#include <utils/Log.h>
@@ -63,6 +64,7 @@
case AIMAGE_FORMAT_YUV_420_888:
case AIMAGE_FORMAT_JPEG:
case AIMAGE_FORMAT_RAW16:
+ case AIMAGE_FORMAT_RAW_DEPTH:
case AIMAGE_FORMAT_RAW_PRIVATE:
case AIMAGE_FORMAT_RAW10:
case AIMAGE_FORMAT_RAW12:
@@ -92,6 +94,7 @@
case AIMAGE_FORMAT_RGBA_FP16:
case AIMAGE_FORMAT_JPEG:
case AIMAGE_FORMAT_RAW16:
+ case AIMAGE_FORMAT_RAW_DEPTH:
case AIMAGE_FORMAT_RAW_PRIVATE:
case AIMAGE_FORMAT_RAW10:
case AIMAGE_FORMAT_RAW12:
diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp
index 768a7a9..ed88cf3 100644
--- a/media/ndk/NdkMediaFormat.cpp
+++ b/media/ndk/NdkMediaFormat.cpp
@@ -371,6 +371,7 @@
EXPORT const char* AMEDIAFORMAT_KEY_TEMPORAL_LAYER_ID = "temporal-layer-id";
EXPORT const char* AMEDIAFORMAT_KEY_TEMPORAL_LAYERING = "ts-schema";
EXPORT const char* AMEDIAFORMAT_KEY_TEXT_FORMAT_DATA = "text-format-data";
+EXPORT const char* AMEDIAFORMAT_KEY_THUMBNAIL_CSD_HEVC = "thumbnail-csd-hevc";
EXPORT const char* AMEDIAFORMAT_KEY_THUMBNAIL_HEIGHT = "thumbnail-height";
EXPORT const char* AMEDIAFORMAT_KEY_THUMBNAIL_TIME = "thumbnail-time";
EXPORT const char* AMEDIAFORMAT_KEY_THUMBNAIL_WIDTH = "thumbnail-width";
diff --git a/media/ndk/OWNERS b/media/ndk/OWNERS
index 11e8340..9dc441e 100644
--- a/media/ndk/OWNERS
+++ b/media/ndk/OWNERS
@@ -1,5 +1,3 @@
marcone@google.com
# For AImage/AImageReader
-etalvala@google.com
-yinchiayeh@google.com
-zhijunhe@google.com
+include platform/frameworks/av:/camera/OWNERS
diff --git a/media/ndk/include/media/NdkMediaFormat.h b/media/ndk/include/media/NdkMediaFormat.h
index 56bcaab..259481d 100644
--- a/media/ndk/include/media/NdkMediaFormat.h
+++ b/media/ndk/include/media/NdkMediaFormat.h
@@ -226,6 +226,7 @@
extern const char* AMEDIAFORMAT_KEY_TARGET_TIME __INTRODUCED_IN(29);
extern const char* AMEDIAFORMAT_KEY_TEMPORAL_LAYER_COUNT __INTRODUCED_IN(29);
extern const char* AMEDIAFORMAT_KEY_TEXT_FORMAT_DATA __INTRODUCED_IN(29);
+extern const char* AMEDIAFORMAT_KEY_THUMBNAIL_CSD_HEVC __INTRODUCED_IN(29);
extern const char* AMEDIAFORMAT_KEY_THUMBNAIL_HEIGHT __INTRODUCED_IN(29);
extern const char* AMEDIAFORMAT_KEY_THUMBNAIL_TIME __INTRODUCED_IN(29);
extern const char* AMEDIAFORMAT_KEY_THUMBNAIL_WIDTH __INTRODUCED_IN(29);
diff --git a/media/ndk/include/private/media/NdkImage.h b/media/ndk/include/private/media/NdkImage.h
new file mode 100644
index 0000000..4368a56
--- /dev/null
+++ b/media/ndk/include/private/media/NdkImage.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2019 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 _PRIVATE_MEDIA_NDKIMAGE_H_
+#define _PRIVATE_MEDIA_NDKIMAGE_H_
+// Formats not listed in the public API, but still available to AImageReader
+enum AIMAGE_PRIVATE_FORMATS {
+ /**
+ * Unprocessed implementation-dependent raw
+ * depth measurements, opaque with 16 bit
+ * samples.
+ *
+ */
+
+ AIMAGE_FORMAT_RAW_DEPTH = 0x1002,
+};
+#endif // _PRIVATE_MEDIA_NDKIMAGE
diff --git a/media/ndk/libmediandk.map.txt b/media/ndk/libmediandk.map.txt
index 9756926..4725e9e 100644
--- a/media/ndk/libmediandk.map.txt
+++ b/media/ndk/libmediandk.map.txt
@@ -135,6 +135,7 @@
AMEDIAFORMAT_KEY_TEMPORAL_LAYER_ID; # var introduced=28
AMEDIAFORMAT_KEY_TEMPORAL_LAYERING; # var introduced=28
AMEDIAFORMAT_KEY_TEXT_FORMAT_DATA; # var introduced=29
+ AMEDIAFORMAT_KEY_THUMBNAIL_CSD_HEVC; # var introduced=29
AMEDIAFORMAT_KEY_THUMBNAIL_HEIGHT; # var introduced=29
AMEDIAFORMAT_KEY_THUMBNAIL_TIME; # var introduced=29
AMEDIAFORMAT_KEY_THUMBNAIL_WIDTH; # var introduced=29
diff --git a/media/ndk/tests/AImageReaderWindowHandleTest.cpp b/media/ndk/tests/AImageReaderWindowHandleTest.cpp
index ef0ff67..5b65064 100644
--- a/media/ndk/tests/AImageReaderWindowHandleTest.cpp
+++ b/media/ndk/tests/AImageReaderWindowHandleTest.cpp
@@ -17,6 +17,7 @@
#include <gtest/gtest.h>
#include <media/NdkImageReader.h>
#include <media/NdkImage.h>
+#include <private/media/NdkImage.h>
#include <mediautils/AImageReaderUtils.h>
#include <gui/IGraphicBufferProducer.h>
#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
@@ -26,6 +27,8 @@
namespace android {
+using HGraphicBufferProducer = hardware::graphics::bufferqueue::V1_0::
+ IGraphicBufferProducer;
using hardware::graphics::bufferqueue::V1_0::utils::H2BGraphicBufferProducer;
using aimg::AImageReader_getHGBPFromHandle;
@@ -182,4 +185,25 @@
EXPECT_TRUE(imageAvailable_) << "Timed out waiting for image data to be handled!\n";
}
+class AImageReaderPrivateFormatTest : public ::testing::Test {
+ public:
+ void SetUp() override {
+ auto status = AImageReader_new(kImageWidth, kImageHeight, AIMAGE_FORMAT_RAW_DEPTH,
+ kMaxImages, &imgReader);
+ EXPECT_TRUE(status == AMEDIA_OK);
+ }
+
+ void TearDown() override {
+ if (imgReader) {
+ AImageReader_delete(imgReader);
+ }
+ }
+ AImageReader *imgReader = nullptr;
+};
+
+TEST_F(AImageReaderPrivateFormatTest, CreateTest) {
+ EXPECT_TRUE(imgReader != nullptr);
+}
+
+
} // namespace android
diff --git a/services/OWNERS b/services/OWNERS
index d5d00da..66a4bcb 100644
--- a/services/OWNERS
+++ b/services/OWNERS
@@ -1,4 +1,7 @@
+chz@google.com
elaurent@google.com
+essick@google.com
etalvala@google.com
gkasten@google.com
hunga@google.com
+marcone@google.com
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 91b7587..40980a6 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -32,6 +32,7 @@
libbinder \
libaudioclient \
libmedialogservice \
+ libmediametrics \
libmediautils \
libnbaio \
libnblog \
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 4033247..b8f88cf 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -224,6 +224,14 @@
// closeOutput_nonvirtual() will remove specified entry from mPlaybackThreads
closeOutput_nonvirtual(mPlaybackThreads.keyAt(0));
}
+ while (!mMmapThreads.isEmpty()) {
+ const audio_io_handle_t io = mMmapThreads.keyAt(0);
+ if (mMmapThreads.valueAt(0)->isOutput()) {
+ closeOutput_nonvirtual(io); // removes entry from mMmapThreads
+ } else {
+ closeInput_nonvirtual(io); // removes entry from mMmapThreads
+ }
+ }
for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
// no mHardwareLock needed, as there are no other references to this
@@ -836,8 +844,10 @@
}
teePatches.push_back({patchRecord, patchTrack});
secondaryThread->addPatchTrack(patchTrack);
- patchTrack->setPeerProxy(patchRecord.get());
- patchRecord->setPeerProxy(patchTrack.get());
+ // In case the downstream patchTrack on the secondaryThread temporarily outlives
+ // our created track, ensure the corresponding patchRecord is still alive.
+ patchTrack->setPeerProxy(patchRecord, true /* holdReference */);
+ patchRecord->setPeerProxy(patchTrack, false /* holdReference */);
}
track->setTeePatches(std::move(teePatches));
}
@@ -3206,24 +3216,44 @@
goto Exit;
}
- // check audio settings permission for global effects
- if (sessionId == AUDIO_SESSION_OUTPUT_MIX && !settingsAllowed()) {
- lStatus = PERMISSION_DENIED;
- goto Exit;
- }
-
- // Session AUDIO_SESSION_OUTPUT_STAGE is reserved for output stage effects
- // that can only be created by audio policy manager
- if (sessionId == AUDIO_SESSION_OUTPUT_STAGE && !isAudioServerUid(callingUid)) {
- lStatus = PERMISSION_DENIED;
- goto Exit;
- }
-
if (mEffectsFactoryHal == 0) {
+ ALOGE("%s: no effects factory hal", __func__);
lStatus = NO_INIT;
goto Exit;
}
+ // check audio settings permission for global effects
+ if (sessionId == AUDIO_SESSION_OUTPUT_MIX) {
+ if (!settingsAllowed()) {
+ ALOGE("%s: no permission for AUDIO_SESSION_OUTPUT_MIX", __func__);
+ lStatus = PERMISSION_DENIED;
+ goto Exit;
+ }
+ } else if (sessionId == AUDIO_SESSION_OUTPUT_STAGE) {
+ if (!isAudioServerUid(callingUid)) {
+ ALOGE("%s: only APM can create using AUDIO_SESSION_OUTPUT_STAGE", __func__);
+ lStatus = PERMISSION_DENIED;
+ goto Exit;
+ }
+
+ if (io == AUDIO_IO_HANDLE_NONE) {
+ ALOGE("%s: APM must specify output when using AUDIO_SESSION_OUTPUT_STAGE", __func__);
+ lStatus = BAD_VALUE;
+ goto Exit;
+ }
+ } else {
+ // general sessionId.
+
+ if (audio_unique_id_get_use(sessionId) != AUDIO_UNIQUE_ID_USE_SESSION) {
+ ALOGE("%s: invalid sessionId %d", __func__, sessionId);
+ lStatus = BAD_VALUE;
+ goto Exit;
+ }
+
+ // TODO: should we check if the callingUid (limited to pid) is in mAudioSessionRefs
+ // to prevent creating an effect when one doesn't actually have track with that session?
+ }
+
{
// Get the full effect descriptor from the uuid/type.
// If the session is the output mix, prefer an auxiliary effect,
@@ -3269,38 +3299,13 @@
// because of code checking output when entering the function.
// Note: io is never 0 when creating an effect on an input
if (io == AUDIO_IO_HANDLE_NONE) {
- if (sessionId == AUDIO_SESSION_OUTPUT_STAGE) {
- // output must be specified by AudioPolicyManager when using session
- // AUDIO_SESSION_OUTPUT_STAGE
- lStatus = BAD_VALUE;
- goto Exit;
- }
// look for the thread where the specified audio session is present
- for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
- uint32_t sessionType = mPlaybackThreads.valueAt(i)->hasAudioSession(sessionId);
- if (sessionType != 0) {
- io = mPlaybackThreads.keyAt(i);
- // thread with same effect session is preferable
- if ((sessionType & ThreadBase::EFFECT_SESSION) != 0) {
- break;
- }
- }
+ io = findIoHandleBySessionId_l(sessionId, mPlaybackThreads);
+ if (io == AUDIO_IO_HANDLE_NONE) {
+ io = findIoHandleBySessionId_l(sessionId, mRecordThreads);
}
if (io == AUDIO_IO_HANDLE_NONE) {
- for (size_t i = 0; i < mRecordThreads.size(); i++) {
- if (mRecordThreads.valueAt(i)->hasAudioSession(sessionId) != 0) {
- io = mRecordThreads.keyAt(i);
- break;
- }
- }
- }
- if (io == AUDIO_IO_HANDLE_NONE) {
- for (size_t i = 0; i < mMmapThreads.size(); i++) {
- if (mMmapThreads.valueAt(i)->hasAudioSession(sessionId) != 0) {
- io = mMmapThreads.keyAt(i);
- break;
- }
- }
+ io = findIoHandleBySessionId_l(sessionId, mMmapThreads);
}
// If no output thread contains the requested session ID, default to
// first output. The effect chain will be moved to the correct output
@@ -3309,6 +3314,21 @@
io = mPlaybackThreads.keyAt(0);
}
ALOGV("createEffect() got io %d for effect %s", io, desc.name);
+ } else if (checkPlaybackThread_l(io) != nullptr) {
+ // allow only one effect chain per sessionId on mPlaybackThreads.
+ for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+ const audio_io_handle_t checkIo = mPlaybackThreads.keyAt(i);
+ if (io == checkIo) continue;
+ const uint32_t sessionType =
+ mPlaybackThreads.valueAt(i)->hasAudioSession(sessionId);
+ if ((sessionType & ThreadBase::EFFECT_SESSION) != 0) {
+ ALOGE("%s: effect %s io %d denied because session %d effect exists on io %d",
+ __func__, desc.name, (int)io, (int)sessionId, (int)checkIo);
+ android_errorWriteLog(0x534e4554, "123237974");
+ lStatus = BAD_VALUE;
+ goto Exit;
+ }
+ }
}
ThreadBase *thread = checkRecordThread_l(io);
if (thread == NULL) {
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 1441e15..ec5dfb1 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -558,6 +558,26 @@
#include "PatchPanel.h"
+ // Find io handle by session id.
+ // Preference is given to an io handle with a matching effect chain to session id.
+ // If none found, AUDIO_IO_HANDLE_NONE is returned.
+ template <typename T>
+ static audio_io_handle_t findIoHandleBySessionId_l(
+ audio_session_t sessionId, const T& threads) {
+ audio_io_handle_t io = AUDIO_IO_HANDLE_NONE;
+
+ for (size_t i = 0; i < threads.size(); i++) {
+ const uint32_t sessionType = threads.valueAt(i)->hasAudioSession(sessionId);
+ if (sessionType != 0) {
+ io = threads.keyAt(i);
+ if ((sessionType & AudioFlinger::ThreadBase::EFFECT_SESSION) != 0) {
+ break; // effect chain here.
+ }
+ }
+ }
+ return io;
+ }
+
// server side of the client's IAudioTrack
class TrackHandle : public android::BnAudioTrack {
public:
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index 676a575..a210a6d 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -527,8 +527,8 @@
}
// tie playback and record tracks together
- mRecord.setTrackAndPeer(tempRecordTrack, tempPatchTrack.get());
- mPlayback.setTrackAndPeer(tempPatchTrack, tempRecordTrack.get());
+ mRecord.setTrackAndPeer(tempRecordTrack, tempPatchTrack);
+ mPlayback.setTrackAndPeer(tempPatchTrack, tempRecordTrack);
// start capture and playback
mRecord.track()->start(AudioSystem::SYNC_EVENT_NONE, AUDIO_SESSION_NONE);
@@ -543,6 +543,7 @@
__func__, mRecord.handle(), mPlayback.handle());
mRecord.stopTrack();
mPlayback.stopTrack();
+ mRecord.clearTrackPeer(); // mRecord stop is synchronous. Break PeerProxy sp<> cycle.
mRecord.closeConnections(panel);
mPlayback.closeConnections(panel);
}
diff --git a/services/audioflinger/PatchPanel.h b/services/audioflinger/PatchPanel.h
index 612855f..181e27c 100644
--- a/services/audioflinger/PatchPanel.h
+++ b/services/audioflinger/PatchPanel.h
@@ -122,12 +122,13 @@
mThread = thread;
mCloseThread = closeThread;
}
- void setTrackAndPeer(const sp<TrackType>& track,
- ThreadBase::PatchProxyBufferProvider *peer) {
+ template <typename T>
+ void setTrackAndPeer(const sp<TrackType>& track, const sp<T> &peer) {
mTrack = track;
mThread->addPatchTrack(mTrack);
- mTrack->setPeerProxy(peer);
+ mTrack->setPeerProxy(peer, true /* holdReference */);
}
+ void clearTrackPeer() { if (mTrack) mTrack->clearPeerProxy(); }
void stopTrack() { if (mTrack) mTrack->stop(); }
void swap(Endpoint &other) noexcept {
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 8f181a4..3ecb37d 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -488,6 +488,8 @@
sp<IBinder> binder = IInterface::asBinder(mPowerManager);
binder->unlinkToDeath(mDeathRecipient);
}
+
+ sendStatistics(true /* force */);
}
status_t AudioFlinger::ThreadBase::readyToRun()
@@ -571,6 +573,15 @@
// sendIoConfigEvent_l() must be called with ThreadBase::mLock held
void AudioFlinger::ThreadBase::sendIoConfigEvent_l(audio_io_config_event event, pid_t pid)
{
+ // The audio statistics history is exponentially weighted to forget events
+ // about five or more seconds in the past. In order to have
+ // crisper statistics for mediametrics, we reset the statistics on
+ // an IoConfigEvent, to reflect different properties for a new device.
+ mIoJitterMs.reset();
+ mLatencyMs.reset();
+ mProcessTimeMs.reset();
+ mTimestampVerifier.discontinuity();
+
sp<ConfigEvent> configEvent = (ConfigEvent *)new IoConfigEvent(event, pid);
sendConfigEvent_l(configEvent);
}
@@ -1651,6 +1662,65 @@
mWaitWorkCV.broadcast();
}
+// Call only from threadLoop() or when it is idle.
+// Do not call from high performance code as this may do binder rpc to the MediaMetrics service.
+void AudioFlinger::ThreadBase::sendStatistics(bool force)
+{
+ // Do not log if we have no stats.
+ // We choose the timestamp verifier because it is the most likely item to be present.
+ const int64_t nstats = mTimestampVerifier.getN() - mLastRecordedTimestampVerifierN;
+ if (nstats == 0) {
+ return;
+ }
+
+ // Don't log more frequently than once per 12 hours.
+ // We use BOOTTIME to include suspend time.
+ const int64_t timeNs = systemTime(SYSTEM_TIME_BOOTTIME);
+ const int64_t sinceNs = timeNs - mLastRecordedTimeNs; // ok if mLastRecordedTimeNs = 0
+ if (!force && sinceNs <= 12 * NANOS_PER_HOUR) {
+ return;
+ }
+
+ mLastRecordedTimestampVerifierN = mTimestampVerifier.getN();
+ mLastRecordedTimeNs = timeNs;
+
+ std::unique_ptr<MediaAnalyticsItem> item(MediaAnalyticsItem::create("audiothread"));
+
+#define MM_PREFIX "android.media.audiothread." // avoid cut-n-paste errors.
+
+ // thread configuration
+ item->setInt32(MM_PREFIX "id", (int32_t)mId); // IO handle
+ // item->setInt32(MM_PREFIX "portId", (int32_t)mPortId);
+ item->setCString(MM_PREFIX "type", threadTypeToString(mType));
+ item->setInt32(MM_PREFIX "sampleRate", (int32_t)mSampleRate);
+ item->setInt64(MM_PREFIX "channelMask", (int64_t)mChannelMask);
+ item->setCString(MM_PREFIX "encoding", toString(mFormat).c_str());
+ item->setInt32(MM_PREFIX "frameCount", (int32_t)mFrameCount);
+ item->setCString(MM_PREFIX "outDevice", toString(mOutDevice).c_str());
+ item->setCString(MM_PREFIX "inDevice", toString(mInDevice).c_str());
+
+ // thread statistics
+ if (mIoJitterMs.getN() > 0) {
+ item->setDouble(MM_PREFIX "ioJitterMs.mean", mIoJitterMs.getMean());
+ item->setDouble(MM_PREFIX "ioJitterMs.std", mIoJitterMs.getStdDev());
+ }
+ if (mProcessTimeMs.getN() > 0) {
+ item->setDouble(MM_PREFIX "processTimeMs.mean", mProcessTimeMs.getMean());
+ item->setDouble(MM_PREFIX "processTimeMs.std", mProcessTimeMs.getStdDev());
+ }
+ const auto tsjitter = mTimestampVerifier.getJitterMs();
+ if (tsjitter.getN() > 0) {
+ item->setDouble(MM_PREFIX "timestampJitterMs.mean", tsjitter.getMean());
+ item->setDouble(MM_PREFIX "timestampJitterMs.std", tsjitter.getStdDev());
+ }
+ if (mLatencyMs.getN() > 0) {
+ item->setDouble(MM_PREFIX "latencyMs.mean", mLatencyMs.getMean());
+ item->setDouble(MM_PREFIX "latencyMs.std", mLatencyMs.getStdDev());
+ }
+
+ item->selfrecord();
+}
+
// ----------------------------------------------------------------------------
// Playback
// ----------------------------------------------------------------------------
@@ -2718,28 +2788,6 @@
}
}
-// hasAudioSession_l() must be called with ThreadBase::mLock held
-uint32_t AudioFlinger::PlaybackThread::hasAudioSession_l(audio_session_t sessionId) const
-{
- uint32_t result = 0;
- if (getEffectChain_l(sessionId) != 0) {
- result = EFFECT_SESSION;
- }
-
- for (size_t i = 0; i < mTracks.size(); ++i) {
- sp<Track> track = mTracks[i];
- if (sessionId == track->sessionId() && !track->isInvalid()) {
- result |= TRACK_SESSION;
- if (track->isFastTrack()) {
- result |= FAST_SESSION;
- }
- break;
- }
- }
-
- return result;
-}
-
uint32_t AudioFlinger::PlaybackThread::getStrategyForSession_l(audio_session_t sessionId)
{
// session AUDIO_SESSION_OUTPUT_MIX is placed in same strategy as MUSIC stream so that
@@ -3447,6 +3495,7 @@
LOG_AUDIO_STATE();
}
mStandby = true;
+ sendStatistics(false /* force */);
}
if (mActiveTracks.isEmpty() && mConfigEvents.isEmpty()) {
@@ -7612,6 +7661,8 @@
// note that threadLoop may still be processing the track at this point [without lock]
recordTrack->mState = TrackBase::PAUSING;
+ // NOTE: Waiting here is important to keep stop synchronous.
+ // This is needed for proper patchRecord peer release.
while (recordTrack->mState == TrackBase::PAUSING && !recordTrack->isInvalid()) {
mWaitWorkCV.broadcast(); // signal thread to stop
mStartStopCond.wait(mLock);
@@ -7669,14 +7720,14 @@
status_t AudioFlinger::RecordThread::setMicrophoneDirection(audio_microphone_direction_t direction)
{
- ALOGV("RecordThread::setMicrophoneDirection");
+ ALOGV("setMicrophoneDirection(%d)", direction);
AutoMutex _l(mLock);
return mInput->stream->setMicrophoneDirection(direction);
}
status_t AudioFlinger::RecordThread::setMicrophoneFieldDimension(float zoom)
{
- ALOGV("RecordThread::setMicrophoneFieldDimension");
+ ALOGV("setMicrophoneFieldDimension(%f)", zoom);
AutoMutex _l(mLock);
return mInput->stream->setMicrophoneFieldDimension(zoom);
}
@@ -8146,27 +8197,6 @@
return 0;
}
-// hasAudioSession_l() must be called with ThreadBase::mLock held
-uint32_t AudioFlinger::RecordThread::hasAudioSession_l(audio_session_t sessionId) const
-{
- uint32_t result = 0;
- if (getEffectChain_l(sessionId) != 0) {
- result = EFFECT_SESSION;
- }
-
- for (size_t i = 0; i < mTracks.size(); ++i) {
- if (sessionId == mTracks[i]->sessionId()) {
- result |= TRACK_SESSION;
- if (mTracks[i]->isFastTrack()) {
- result |= FAST_SESSION;
- }
- break;
- }
- }
-
- return result;
-}
-
KeyedVector<audio_session_t, bool> AudioFlinger::RecordThread::sessionIds() const
{
KeyedVector<audio_session_t, bool> ids;
@@ -8674,9 +8704,11 @@
while (!exitPending())
{
- Mutex::Autolock _l(mLock);
Vector< sp<EffectChain> > effectChains;
+ { // under Thread lock
+ Mutex::Autolock _l(mLock);
+
if (mSignalPending) {
// A signal was raised while we were unlocked
mSignalPending = false;
@@ -8711,10 +8743,13 @@
updateMetadata_l();
lockEffectChains_l(effectChains);
+ } // release Thread lock
+
for (size_t i = 0; i < effectChains.size(); i ++) {
- effectChains[i]->process_l();
+ effectChains[i]->process_l(); // Thread is not locked, but effect chain is locked
}
- // enable changes in effect chain
+
+ // enable changes in effect chain, including moving to another thread.
unlockEffectChains(effectChains);
// Effect chains will be actually deleted here if they were removed from
// mEffectChains list during mixing or effects processing
@@ -8975,28 +9010,6 @@
return mEffectChains.size();
}
-// hasAudioSession_l() must be called with ThreadBase::mLock held
-uint32_t AudioFlinger::MmapThread::hasAudioSession_l(audio_session_t sessionId) const
-{
- uint32_t result = 0;
- if (getEffectChain_l(sessionId) != 0) {
- result = EFFECT_SESSION;
- }
-
- for (size_t i = 0; i < mActiveTracks.size(); i++) {
- sp<MmapTrack> track = mActiveTracks[i];
- if (sessionId == track->sessionId()) {
- result |= TRACK_SESSION;
- if (track->isFastTrack()) {
- result |= FAST_SESSION;
- }
- break;
- }
- }
-
- return result;
-}
-
void AudioFlinger::MmapThread::threadLoop_standby()
{
mHalStream->standby();
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 1afea08..47e580b 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -356,6 +356,27 @@
return hasAudioSession_l(sessionId);
}
+ template <typename T>
+ uint32_t hasAudioSession_l(audio_session_t sessionId, const T& tracks) const {
+ uint32_t result = 0;
+ if (getEffectChain_l(sessionId) != 0) {
+ result = EFFECT_SESSION;
+ }
+ for (size_t i = 0; i < tracks.size(); ++i) {
+ const sp<TrackBase>& track = tracks[i];
+ if (sessionId == track->sessionId()
+ && !track->isInvalid() // not yet removed from tracks.
+ && !track->isTerminated()) {
+ result |= TRACK_SESSION;
+ if (track->isFastTrack()) {
+ result |= FAST_SESSION; // caution, only represents first track.
+ }
+ break;
+ }
+ }
+ return result;
+ }
+
// the value returned by default implementation is not important as the
// strategy is only meaningful for PlaybackThread which implements this method
virtual uint32_t getStrategyForSession_l(audio_session_t sessionId __unused)
@@ -399,6 +420,9 @@
virtual void dump(int fd, const Vector<String16>& args) = 0;
+ // deliver stats to mediametrics.
+ void sendStatistics(bool force);
+
mutable Mutex mLock;
protected:
@@ -522,6 +546,10 @@
audio_utils::Statistics<double> mProcessTimeMs{0.995 /* alpha */};
audio_utils::Statistics<double> mLatencyMs{0.995 /* alpha */};
+ // Save the last count when we delivered statistics to mediametrics.
+ int64_t mLastRecordedTimestampVerifierN = 0;
+ int64_t mLastRecordedTimeNs = 0; // BOOTTIME to include suspend.
+
bool mIsMsdDevice = false;
// A condition that must be evaluated by the thread loop has changed and
// we must not wait for async write callback in the thread loop before evaluating it
@@ -803,7 +831,9 @@
virtual status_t addEffectChain_l(const sp<EffectChain>& chain);
virtual size_t removeEffectChain_l(const sp<EffectChain>& chain);
- virtual uint32_t hasAudioSession_l(audio_session_t sessionId) const;
+ uint32_t hasAudioSession_l(audio_session_t sessionId) const override {
+ return ThreadBase::hasAudioSession_l(sessionId, mTracks);
+ }
virtual uint32_t getStrategyForSession_l(audio_session_t sessionId);
@@ -1543,7 +1573,9 @@
virtual status_t addEffectChain_l(const sp<EffectChain>& chain);
virtual size_t removeEffectChain_l(const sp<EffectChain>& chain);
- virtual uint32_t hasAudioSession_l(audio_session_t sessionId) const;
+ uint32_t hasAudioSession_l(audio_session_t sessionId) const override {
+ return ThreadBase::hasAudioSession_l(sessionId, mTracks);
+ }
// Return the set of unique session IDs across all tracks.
// The keys are the session IDs, and the associated values are meaningless.
@@ -1718,7 +1750,10 @@
virtual status_t checkEffectCompatibility_l(const effect_descriptor_t *desc,
audio_session_t sessionId);
- virtual uint32_t hasAudioSession_l(audio_session_t sessionId) const;
+ uint32_t hasAudioSession_l(audio_session_t sessionId) const override {
+ // Note: using mActiveTracks as no mTracks here.
+ return ThreadBase::hasAudioSession_l(sessionId, mActiveTracks);
+ }
virtual status_t setSyncEvent(const sp<SyncEvent>& event);
virtual bool isValidSyncEvent(const sp<SyncEvent>& event) const;
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index 0ba0ab4..4402d99 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -94,6 +94,9 @@
virtual void invalidate() { mIsInvalid = true; }
bool isInvalid() const { return mIsInvalid; }
+ void terminate() { mTerminated = true; }
+ bool isTerminated() const { return mTerminated; }
+
audio_attributes_t attributes() const { return mAttr; }
#ifdef TEE_SINK
@@ -228,14 +231,6 @@
return mState == STOPPING_2;
}
- bool isTerminated() const {
- return mTerminated;
- }
-
- void terminate() {
- mTerminated = true;
- }
-
// Upper case characters are final states.
// Lower case characters are transitory.
const char *getTrackStateString() const {
@@ -337,10 +332,19 @@
PatchTrackBase(sp<ClientProxy> proxy, const ThreadBase& thread,
const Timeout& timeout);
void setPeerTimeout(std::chrono::nanoseconds timeout);
- void setPeerProxy(PatchProxyBufferProvider *proxy) { mPeerProxy = proxy; }
+ template <typename T>
+ void setPeerProxy(const sp<T> &proxy, bool holdReference) {
+ mPeerReferenceHold = holdReference ? proxy : nullptr;
+ mPeerProxy = proxy.get();
+ }
+ void clearPeerProxy() {
+ mPeerReferenceHold.clear();
+ mPeerProxy = nullptr;
+ }
protected:
const sp<ClientProxy> mProxy;
+ sp<RefBase> mPeerReferenceHold; // keeps mPeerProxy alive during access.
PatchProxyBufferProvider* mPeerProxy = nullptr;
struct timespec mPeerTimeout{};
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index ad78a45..5a43696 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -1723,6 +1723,7 @@
AudioFlinger::PlaybackThread::PatchTrack::~PatchTrack()
{
+ ALOGV("%s(%d)", __func__, mId);
}
status_t AudioFlinger::PlaybackThread::PatchTrack::start(AudioSystem::sync_event_t event,
@@ -2193,6 +2194,7 @@
AudioFlinger::RecordThread::PatchRecord::~PatchRecord()
{
+ ALOGV("%s(%d)", __func__, mId);
}
// AudioBufferProvider interface
diff --git a/services/audiopolicy/Android.mk b/services/audiopolicy/Android.mk
index 9e4eebc..3badda1 100644
--- a/services/audiopolicy/Android.mk
+++ b/services/audiopolicy/Android.mk
@@ -62,10 +62,6 @@
$(error Configurable policy does not support legacy conf file)
endif #ifneq ($(USE_XML_AUDIO_POLICY_CONF), 1)
-LOCAL_REQUIRED_MODULES := \
- parameter-framework.policy \
- audio_policy_criteria.conf \
-
LOCAL_C_INCLUDES += frameworks/av/services/audiopolicy/engineconfigurable/include
LOCAL_C_INCLUDES += frameworks/av/include
diff --git a/services/audiopolicy/common/include/Volume.h b/services/audiopolicy/common/include/Volume.h
index 48b5271..561f100 100644
--- a/services/audiopolicy/common/include/Volume.h
+++ b/services/audiopolicy/common/include/Volume.h
@@ -16,19 +16,22 @@
#pragma once
+#include <media/AudioCommonTypes.h>
#include <system/audio.h>
#include <utils/Log.h>
#include <math.h>
namespace android {
+
/**
* VolumeSource is the discriminent for volume management on an output.
* It used to be the stream type by legacy, it may be host volume group or a volume curves if
- * we allow to have more than one curve per volume group.
+ * we allow to have more than one curve per volume group (mandatory to get rid of AudioServer
+ * stream aliases.
*/
-enum VolumeSource : std::underlying_type<audio_stream_type_t>::type;
-static const VolumeSource VOLUME_SOURCE_NONE = static_cast<VolumeSource>(AUDIO_STREAM_DEFAULT);
+enum VolumeSource : std::underlying_type<volume_group_t>::type;
+static const VolumeSource VOLUME_SOURCE_NONE = static_cast<VolumeSource>(VOLUME_GROUP_NONE);
static inline VolumeSource streamToVolumeSource(audio_stream_type_t stream) {
return static_cast<VolumeSource>(stream);
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
index 803cfac..e071fe0 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
@@ -29,7 +29,7 @@
namespace android {
-class AudioMix;
+class AudioPolicyMix;
class AudioPolicyClientInterface;
// descriptor for audio inputs. Used to maintain current configuration of each opened audio input
@@ -53,7 +53,7 @@
void dump(String8 *dst) const override;
audio_io_handle_t mIoHandle = AUDIO_IO_HANDLE_NONE; // input handle
- AudioMix *mPolicyMix = nullptr; // non NULL when used by a dynamic policy
+ wp<AudioPolicyMix> mPolicyMix; // non NULL when used by a dynamic policy
const sp<IOProfile> mProfile; // I/O profile this output derives from
virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index 704f404..cd54085 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -34,7 +34,7 @@
namespace android {
class IOProfile;
-class AudioMix;
+class AudioPolicyMix;
class AudioPolicyClientInterface;
class ActivityTracking
@@ -107,7 +107,7 @@
};
/**
* Note: volume activities shall be indexed by CurvesId if we want to allow multiple
- * curves per volume group, inferring a mute management or volume balancing between HW and SW is
+ * curves per volume source, inferring a mute management or volume balancing between HW and SW is
* done
*/
using VolumeActivities = std::map<VolumeSource, VolumeActivity>;
@@ -157,7 +157,7 @@
virtual uint32_t latency() { return 0; }
virtual bool isFixedVolume(audio_devices_t device);
virtual bool setVolume(float volumeDb,
- audio_stream_type_t stream,
+ VolumeSource volumeSource, const StreamTypeVector &streams,
audio_devices_t device,
uint32_t delayMs,
bool force);
@@ -221,7 +221,7 @@
}
void setCurVolume(VolumeSource vs, float volumeDb)
{
- // Even if not activity for this group registered, need to create anyway
+ // Even if not activity for this source registered, need to create anyway
mVolumeActivities[vs].setVolume(volumeDb);
}
float getCurVolume(VolumeSource vs) const
@@ -280,8 +280,13 @@
return mActiveClients;
}
+ bool useHwGain() const
+ {
+ return !devices().isEmpty() ? devices().itemAt(0)->hasGainController() : false;
+ }
+
DeviceVector mDevices; /**< current devices this output is routed to */
- AudioMix *mPolicyMix = nullptr; // non NULL when used by a dynamic policy
+ wp<AudioPolicyMix> mPolicyMix; // non NULL when used by a dynamic policy
protected:
const sp<AudioPort> mPort;
@@ -328,7 +333,7 @@
}
}
virtual bool setVolume(float volumeDb,
- audio_stream_type_t stream,
+ VolumeSource volumeSource, const StreamTypeVector &streams,
audio_devices_t device,
uint32_t delayMs,
bool force);
@@ -402,7 +407,7 @@
void dump(String8 *dst) const override;
virtual bool setVolume(float volumeDb,
- audio_stream_type_t stream,
+ VolumeSource volumeSource, const StreamTypeVector &streams,
audio_devices_t device,
uint32_t delayMs,
bool force);
@@ -422,7 +427,7 @@
bool isActive(VolumeSource volumeSource, uint32_t inPastMs = 0) const;
/**
- * return whether any source contributing to VolumeSource is playing remotely, override
+ * return whether any source contributing to VolumeSource is playing remotely, override
* to change the definition of
* local/remote playback, used for instance by notification manager to not make
* media players lose audio focus when not playing locally
@@ -488,8 +493,8 @@
/**
* @brief isAnyOutputActive checks if any output is active (aka playing) except the one(s) that
* hold the volume source to be ignored
- * @param volumeSourceToIgnore source not considered in the activity detection
- * @return true if any output is active for any source except the one to be ignored
+ * @param volumeSourceToIgnore source not to be considered in the activity detection
+ * @return true if any output is active for any volume source except the one to be ignored
*/
bool isAnyOutputActive(VolumeSource volumeSourceToIgnore) const
{
@@ -518,8 +523,8 @@
/**
* @brief isAnyOutputActive checks if any output is active (aka playing) except the one(s) that
* hold the volume source to be ignored
- * @param volumeSourceToIgnore source not considered in the activity detection
- * @return true if any output is active for any source except the one to be ignored
+ * @param volumeSourceToIgnore source not to be considered in the activity detection
+ * @return true if any output is active for any volume source except the one to be ignored
*/
bool isAnyOutputActive(VolumeSource volumeSourceToIgnore) const
{
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
index d6f24b2..7a9c26e 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
@@ -31,24 +31,19 @@
/**
* custom mix entry in mPolicyMixes
*/
-class AudioPolicyMix : public RefBase {
+class AudioPolicyMix : public AudioMix, public RefBase {
public:
- AudioPolicyMix() {}
+ AudioPolicyMix(const AudioMix &mix) : AudioMix(mix) {}
+ AudioPolicyMix(const AudioPolicyMix&) = delete;
+ AudioPolicyMix& operator=(const AudioPolicyMix&) = delete;
- const sp<SwAudioOutputDescriptor> &getOutput() const;
-
- void setOutput(sp<SwAudioOutputDescriptor> &output);
-
- void clearOutput();
-
- android::AudioMix *getMix();
-
- void setMix(const AudioMix &mix);
+ const sp<SwAudioOutputDescriptor> &getOutput() const { return mOutput; }
+ void setOutput(const sp<SwAudioOutputDescriptor> &output) { mOutput = output; }
+ void clearOutput() { mOutput.clear(); }
void dump(String8 *dst, int spaces, int index) const;
private:
- AudioMix mMix; // Audio policy mix descriptor
sp<SwAudioOutputDescriptor> mOutput; // Corresponding output stream
};
@@ -77,21 +72,19 @@
sp<DeviceDescriptor> getDeviceAndMixForInputSource(audio_source_t inputSource,
const DeviceVector &availableDeviceTypes,
- AudioMix **policyMix) const;
+ sp<AudioPolicyMix> *policyMix) const;
/**
* @brief try to find a matching mix for a given output descriptor and returns the associated
* output device.
* @param output to be considered
* @param availableOutputDevices list of output devices currently reachable
- * @param policyMix to be returned if any mix matching ouput descriptor
* @return device selected from the mix attached to the output, null pointer otherwise
*/
sp<DeviceDescriptor> getDeviceAndMixForOutput(const sp<SwAudioOutputDescriptor> &output,
- const DeviceVector &availableOutputDevices,
- AudioMix **policyMix = nullptr);
+ const DeviceVector &availableOutputDevices);
- status_t getInputMixForAttr(audio_attributes_t attr, AudioMix **policyMix);
+ status_t getInputMixForAttr(audio_attributes_t attr, sp<AudioPolicyMix> *policyMix);
status_t setUidDeviceAffinities(uid_t uid, const Vector<AudioDeviceTypeAddr>& devices);
status_t removeUidDeviceAffinities(uid_t uid);
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
index 1fa1123..635de6f 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -22,6 +22,7 @@
#include <AudioPolicyInterface.h>
#include "AudioInputDescriptor.h"
#include "AudioGain.h"
+#include "AudioPolicyMix.h"
#include "HwModule.h"
namespace android {
@@ -308,16 +309,17 @@
const int delta = active ? 1 : -1;
mGlobalActiveCount += delta;
+ sp<AudioPolicyMix> policyMix = mPolicyMix.promote();
if ((oldGlobalActiveCount == 0) && (mGlobalActiveCount > 0)) {
- if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
+ if ((policyMix != NULL) && ((policyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
{
- mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mDeviceAddress,
+ mClientInterface->onDynamicPolicyMixStateUpdate(policyMix->mDeviceAddress,
MIX_STATE_MIXING);
}
} else if ((oldGlobalActiveCount > 0) && (mGlobalActiveCount == 0)) {
- if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
+ if ((policyMix != NULL) && ((policyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
{
- mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mDeviceAddress,
+ mClientInterface->onDynamicPolicyMixStateUpdate(policyMix->mDeviceAddress,
MIX_STATE_IDLE);
}
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index fd33649..97b7a01 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -19,10 +19,12 @@
#include <AudioPolicyInterface.h>
#include "AudioOutputDescriptor.h"
+#include "AudioPolicyMix.h"
#include "IOProfile.h"
#include "AudioGain.h"
#include "Volume.h"
#include "HwModule.h"
+#include "TypeConverter.h"
#include <media/AudioParameter.h>
#include <media/AudioPolicy.h>
@@ -111,9 +113,10 @@
}
mGlobalActiveCount += delta;
- if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
+ sp<AudioPolicyMix> policyMix = mPolicyMix.promote();
+ if ((policyMix != NULL) && ((policyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
if ((oldGlobalActiveCount == 0) || (mGlobalActiveCount == 0)) {
- mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mDeviceAddress,
+ mClientInterface->onDynamicPolicyMixStateUpdate(policyMix->mDeviceAddress,
mGlobalActiveCount > 0 ? MIX_STATE_MIXING : MIX_STATE_IDLE);
}
}
@@ -150,17 +153,18 @@
}
bool AudioOutputDescriptor::setVolume(float volumeDb,
- audio_stream_type_t stream,
- audio_devices_t device __unused,
+ VolumeSource volumeSource,
+ const StreamTypeVector &/*streams*/,
+ audio_devices_t /*device*/,
uint32_t delayMs,
bool force)
{
// We actually change the volume if:
// - the float value returned by computeVolume() changed
// - the force flag is set
- if (volumeDb != getCurVolume(static_cast<VolumeSource>(stream)) || force) {
- ALOGV("setVolume() for stream %d, volume %f, delay %d", stream, volumeDb, delayMs);
- setCurVolume(static_cast<VolumeSource>(stream), volumeDb);
+ if (volumeDb != getCurVolume(volumeSource) || force) {
+ ALOGV("%s for volumeSrc %d, volume %f, delay %d", __func__, volumeSource, volumeDb, delayMs);
+ setCurVolume(volumeSource, volumeDb);
return true;
}
return false;
@@ -389,23 +393,33 @@
}
bool SwAudioOutputDescriptor::setVolume(float volumeDb,
- audio_stream_type_t stream,
+ VolumeSource vs, const StreamTypeVector &streamTypes,
audio_devices_t device,
uint32_t delayMs,
bool force)
{
- if (!AudioOutputDescriptor::setVolume(volumeDb, stream, device, delayMs, force)) {
+ StreamTypeVector streams = streamTypes;
+ if (!AudioOutputDescriptor::setVolume(volumeDb, vs, streamTypes, device, delayMs, force)) {
return false;
}
- if (!devices().isEmpty()) {
- // Assume first device to check upon Gain Crontroller availability
- const auto &devicePort = devices().itemAt(0);
- ALOGV("%s: device %s hasGC %d", __FUNCTION__,
- devicePort->toString().c_str(), devices().itemAt(0)->hasGainController(true));
- if (devicePort->hasGainController(true)) {
+ if (streams.empty()) {
+ streams.push_back(AUDIO_STREAM_MUSIC);
+ }
+ for (const auto& devicePort : devices()) {
+ // APM loops on all group, so filter on active group to set the port gain,
+ // let the other groups set the stream volume as per legacy
+ // TODO: Pass in the device address and check against it.
+ if (device == devicePort->type() &&
+ devicePort->hasGainController(true) && isActive(vs)) {
+ ALOGV("%s: device %s has gain controller", __func__, devicePort->toString().c_str());
+ // @todo: here we might be in trouble if the SwOutput has several active clients with
+ // different Volume Source (or if we allow several curves within same volume group)
+ //
// @todo: default stream volume to max (0) when using HW Port gain?
float volumeAmpl = Volume::DbToAmpl(0);
- mClientInterface->setStreamVolume(stream, volumeAmpl, mIoHandle, delayMs);
+ for (const auto &stream : streams) {
+ mClientInterface->setStreamVolume(stream, volumeAmpl, mIoHandle, delayMs);
+ }
AudioGains gains = devicePort->getGains();
int gainMinValueInMb = gains[0]->getMinValueInMb();
@@ -422,11 +436,15 @@
}
}
// Force VOICE_CALL to track BLUETOOTH_SCO stream volume when bluetooth audio is enabled
- float volumeAmpl = Volume::DbToAmpl(getCurVolume(static_cast<VolumeSource>(stream)));
- if (stream == AUDIO_STREAM_BLUETOOTH_SCO) {
+ float volumeAmpl = Volume::DbToAmpl(getCurVolume(vs));
+ if (hasStream(streams, AUDIO_STREAM_BLUETOOTH_SCO)) {
mClientInterface->setStreamVolume(AUDIO_STREAM_VOICE_CALL, volumeAmpl, mIoHandle, delayMs);
}
- mClientInterface->setStreamVolume(stream, volumeAmpl, mIoHandle, delayMs);
+ for (const auto &stream : streams) {
+ ALOGV("%s output %d for volumeSource %d, volume %f, delay %d stream=%s", __func__,
+ mIoHandle, vs, volumeDb, delayMs, toString(stream).c_str());
+ mClientInterface->setStreamVolume(stream, volumeAmpl, mIoHandle, delayMs);
+ }
return true;
}
@@ -616,12 +634,13 @@
bool HwAudioOutputDescriptor::setVolume(float volumeDb,
- audio_stream_type_t stream,
+ VolumeSource volumeSource, const StreamTypeVector &streams,
audio_devices_t device,
uint32_t delayMs,
bool force)
{
- bool changed = AudioOutputDescriptor::setVolume(volumeDb, stream, device, delayMs, force);
+ bool changed =
+ AudioOutputDescriptor::setVolume(volumeDb, volumeSource, streams, device, delayMs, force);
if (changed) {
// TODO: use gain controller on source device if any to adjust volume
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
index 23d764e..f7289ca 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -27,51 +27,26 @@
namespace android {
-void AudioPolicyMix::setOutput(sp<SwAudioOutputDescriptor> &output)
-{
- mOutput = output;
-}
-
-const sp<SwAudioOutputDescriptor> &AudioPolicyMix::getOutput() const
-{
- return mOutput;
-}
-
-void AudioPolicyMix::clearOutput()
-{
- mOutput.clear();
-}
-
-void AudioPolicyMix::setMix(const AudioMix &mix)
-{
- mMix = mix;
-}
-
-android::AudioMix *AudioPolicyMix::getMix()
-{
- return &mMix;
-}
-
void AudioPolicyMix::dump(String8 *dst, int spaces, int index) const
{
dst->appendFormat("%*sAudio Policy Mix %d:\n", spaces, "", index + 1);
std::string mixTypeLiteral;
- if (!MixTypeConverter::toString(mMix.mMixType, mixTypeLiteral)) {
- ALOGE("%s: failed to convert mix type %d", __FUNCTION__, mMix.mMixType);
+ if (!MixTypeConverter::toString(mMixType, mixTypeLiteral)) {
+ ALOGE("%s: failed to convert mix type %d", __FUNCTION__, mMixType);
return;
}
dst->appendFormat("%*s- mix type: %s\n", spaces, "", mixTypeLiteral.c_str());
std::string routeFlagLiteral;
- RouteFlagTypeConverter::maskToString(mMix.mRouteFlags, routeFlagLiteral);
+ RouteFlagTypeConverter::maskToString(mRouteFlags, routeFlagLiteral);
dst->appendFormat("%*s- Route Flags: %s\n", spaces, "", routeFlagLiteral.c_str());
- dst->appendFormat("%*s- device type: %s\n", spaces, "", toString(mMix.mDeviceType).c_str());
+ dst->appendFormat("%*s- device type: %s\n", spaces, "", toString(mDeviceType).c_str());
- dst->appendFormat("%*s- device address: %s\n", spaces, "", mMix.mDeviceAddress.string());
+ dst->appendFormat("%*s- device address: %s\n", spaces, "", mDeviceAddress.string());
int indexCriterion = 0;
- for (const auto &criterion : mMix.mCriteria) {
+ for (const auto &criterion : mCriteria) {
dst->appendFormat("%*s- Criterion %d:\n", spaces + 2, "", indexCriterion++);
std::string usageLiteral;
@@ -81,7 +56,7 @@
}
dst->appendFormat("%*s- Usage:%s\n", spaces + 4, "", usageLiteral.c_str());
- if (mMix.mMixType == MIX_TYPE_RECORDERS) {
+ if (mMixType == MIX_TYPE_RECORDERS) {
std::string sourceLiteral;
if (!SourceTypeConverter::toString(criterion.mValue.mSource, sourceLiteral)) {
ALOGE("%s: failed to convert source %d", __FUNCTION__, criterion.mValue.mSource);
@@ -109,12 +84,11 @@
ALOGE("registerPolicyMixes(): mix for address %s already registered", address.string());
return BAD_VALUE;
}
- sp<AudioPolicyMix> policyMix = new AudioPolicyMix();
- policyMix->setMix(mix);
+ sp<AudioPolicyMix> policyMix = new AudioPolicyMix(mix);
add(address, policyMix);
if (desc != 0) {
- desc->mPolicyMix = policyMix->getMix();
+ desc->mPolicyMix = policyMix;
policyMix->setOutput(desc);
}
return NO_ERROR;
@@ -168,15 +142,14 @@
continue;
}
- AudioMix *mix = policyMix->getMix();
- const bool primaryOutputMix = !is_mix_loopback_render(mix->mRouteFlags);
+ const bool primaryOutputMix = !is_mix_loopback_render(policyMix->mRouteFlags);
if (primaryOutputMix && primaryDesc != 0) {
ALOGV("%s: Skiping %zu: Primary output already found", __func__, i);
continue; // Primary output already found
}
- switch (mixMatch(mix, i, attributes, uid)) {
+ switch (mixMatch(policyMix.get(), i, attributes, uid)) {
case MixMatchStatus::INVALID_MIX: return BAD_VALUE; // TODO: Do we really want to abort?
case MixMatchStatus::NO_MATCH:
ALOGV("%s: Mix %zu: does not match", __func__, i);
@@ -184,7 +157,7 @@
case MixMatchStatus::MATCH:;
}
- policyDesc->mPolicyMix = mix;
+ policyDesc->mPolicyMix = policyMix;
if (primaryOutputMix) {
primaryDesc = policyDesc;
ALOGV("%s: Mix %zu: set primary desc", __func__, i);
@@ -327,17 +300,13 @@
sp<DeviceDescriptor> AudioPolicyMixCollection::getDeviceAndMixForOutput(
const sp<SwAudioOutputDescriptor> &output,
- const DeviceVector &availableOutputDevices,
- AudioMix **policyMix)
+ const DeviceVector &availableOutputDevices)
{
for (size_t i = 0; i < size(); i++) {
if (valueAt(i)->getOutput() == output) {
- AudioMix *mix = valueAt(i)->getMix();
- if (policyMix != nullptr)
- *policyMix = mix;
// This Desc is involved in a Mix, which has the highest prio
- audio_devices_t deviceType = mix->mDeviceType;
- String8 address = mix->mDeviceAddress;
+ audio_devices_t deviceType = valueAt(i)->mDeviceType;
+ String8 address = valueAt(i)->mDeviceAddress;
ALOGV("%s: device (0x%x, addr=%s) forced by mix",
__FUNCTION__, deviceType, address.c_str());
return availableOutputDevices.getDevice(deviceType, address, AUDIO_FORMAT_DEFAULT);
@@ -347,10 +316,12 @@
}
sp<DeviceDescriptor> AudioPolicyMixCollection::getDeviceAndMixForInputSource(
- audio_source_t inputSource, const DeviceVector &availDevices, AudioMix **policyMix) const
+ audio_source_t inputSource,
+ const DeviceVector &availDevices,
+ sp<AudioPolicyMix> *policyMix) const
{
for (size_t i = 0; i < size(); i++) {
- AudioMix *mix = valueAt(i)->getMix();
+ AudioPolicyMix *mix = valueAt(i).get();
if (mix->mMixType != MIX_TYPE_RECORDERS) {
continue;
}
@@ -365,7 +336,7 @@
auto mixDevice =
availDevices.getDevice(device, mix->mDeviceAddress, AUDIO_FORMAT_DEFAULT);
if (mixDevice != nullptr) {
- if (policyMix != NULL) {
+ if (policyMix != nullptr) {
*policyMix = mix;
}
return mixDevice;
@@ -377,7 +348,8 @@
return nullptr;
}
-status_t AudioPolicyMixCollection::getInputMixForAttr(audio_attributes_t attr, AudioMix **policyMix)
+status_t AudioPolicyMixCollection::getInputMixForAttr(
+ audio_attributes_t attr, sp<AudioPolicyMix> *policyMix)
{
if (strncmp(attr.tags, "addr=", strlen("addr=")) != 0) {
return BAD_VALUE;
@@ -387,9 +359,8 @@
#ifdef LOG_NDEBUG
ALOGV("getInputMixForAttr looking for address %s\n mixes available:", address.string());
for (size_t i = 0; i < size(); i++) {
- sp<AudioPolicyMix> policyMix = valueAt(i);
- const AudioMix *mix = policyMix->getMix();
- ALOGV("\tmix %zu address=%s", i, mix->mDeviceAddress.string());
+ sp<AudioPolicyMix> audioPolicyMix = valueAt(i);
+ ALOGV("\tmix %zu address=%s", i, audioPolicyMix->mDeviceAddress.string());
}
#endif
@@ -399,13 +370,14 @@
return BAD_VALUE;
}
sp<AudioPolicyMix> audioPolicyMix = valueAt(index);
- AudioMix *mix = audioPolicyMix->getMix();
- if (mix->mMixType != MIX_TYPE_PLAYERS) {
+ if (audioPolicyMix->mMixType != MIX_TYPE_PLAYERS) {
ALOGW("getInputMixForAttr() bad policy mix type for address %s", address.string());
return BAD_VALUE;
}
- *policyMix = mix;
+ if (policyMix != nullptr) {
+ *policyMix = audioPolicyMix;
+ }
return NO_ERROR;
}
@@ -416,7 +388,7 @@
// for each player mix: add a rule to match or exclude the uid based on the device
for (size_t i = 0; i < size(); i++) {
- const AudioMix *mix = valueAt(i)->getMix();
+ const AudioPolicyMix *mix = valueAt(i).get();
if (mix->mMixType != MIX_TYPE_PLAYERS) {
continue;
}
@@ -445,7 +417,7 @@
// for each player mix: remove existing rules that match or exclude this uid
for (size_t i = 0; i < size(); i++) {
bool foundUidRule = false;
- const AudioMix *mix = valueAt(i)->getMix();
+ const AudioPolicyMix *mix = valueAt(i).get();
if (mix->mMixType != MIX_TYPE_PLAYERS) {
continue;
}
@@ -473,7 +445,7 @@
// for each player mix: find rules that don't exclude this uid, and add the device to the list
for (size_t i = 0; i < size(); i++) {
bool ruleAllowsUid = true;
- const AudioMix *mix = valueAt(i)->getMix();
+ const AudioPolicyMix *mix = valueAt(i).get();
if (mix->mMixType != MIX_TYPE_PLAYERS) {
continue;
}
diff --git a/services/audiopolicy/engine/common/Android.bp b/services/audiopolicy/engine/common/Android.bp
index e6ede07..d0775ad 100644
--- a/services/audiopolicy/engine/common/Android.bp
+++ b/services/audiopolicy/engine/common/Android.bp
@@ -17,3 +17,31 @@
host_supported: true,
export_include_dirs: ["include"],
}
+
+cc_library_static {
+ name: "libaudiopolicyengine_common",
+ srcs: [
+ "src/EngineBase.cpp",
+ "src/ProductStrategy.cpp",
+ "src/VolumeCurve.cpp",
+ "src/VolumeGroup.cpp",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+ header_libs: [
+ "libbase_headers",
+ "libaudiopolicycommon",
+ "libaudiopolicyengine_common_headers",
+ "libaudiopolicyengine_interface_headers",
+ ],
+ export_header_lib_headers: [
+ "libaudiopolicyengine_common_headers",
+ ],
+ static_libs: [
+ "libaudiopolicycomponents",
+ "libaudiopolicyengine_config",
+ ],
+}
diff --git a/services/audiopolicy/engine/common/include/EngineBase.h b/services/audiopolicy/engine/common/include/EngineBase.h
index 6ff8512..cedc78f 100644
--- a/services/audiopolicy/engine/common/include/EngineBase.h
+++ b/services/audiopolicy/engine/common/include/EngineBase.h
@@ -84,10 +84,6 @@
volume_group_t getVolumeGroupForStreamType(audio_stream_type_t stream) const override;
- StreamTypeVector getStreamTypesForVolumeGroup(volume_group_t volumeGroup) const override;
-
- AttributesVector getAllAttributesForVolumeGroup(volume_group_t volumeGroup) const override;
-
status_t listAudioVolumeGroups(AudioVolumeGroupVector &groups) const override;
void dump(String8 *dst) const override;
@@ -112,7 +108,7 @@
VolumeSource toVolumeSource(audio_stream_type_t stream) const
{
- return static_cast<VolumeSource>(stream);
+ return static_cast<VolumeSource>(getVolumeGroupForStreamType(stream));
}
status_t switchVolumeCurve(audio_stream_type_t streamSrc, audio_stream_type_t streamDst);
diff --git a/services/audiopolicy/engine/common/include/ProductStrategy.h b/services/audiopolicy/engine/common/include/ProductStrategy.h
index 767a8ed..1a2a198 100644
--- a/services/audiopolicy/engine/common/include/ProductStrategy.h
+++ b/services/audiopolicy/engine/common/include/ProductStrategy.h
@@ -152,6 +152,8 @@
volume_group_t getVolumeGroupForStreamType(audio_stream_type_t stream) const;
+ volume_group_t getDefaultVolumeGroup() const;
+
product_strategy_t getDefault() const;
void dump(String8 *dst, int spaces = 0) const;
diff --git a/services/audiopolicy/engine/common/src/EngineBase.cpp b/services/audiopolicy/engine/common/src/EngineBase.cpp
index 4fe7b42..07a7e65 100644
--- a/services/audiopolicy/engine/common/src/EngineBase.cpp
+++ b/services/audiopolicy/engine/common/src/EngineBase.cpp
@@ -218,6 +218,9 @@
VolumeCurves *EngineBase::getVolumeCurvesForStreamType(audio_stream_type_t stream) const
{
volume_group_t volGr = mProductStrategies.getVolumeGroupForStreamType(stream);
+ if (volGr == VOLUME_GROUP_NONE) {
+ volGr = mProductStrategies.getDefaultVolumeGroup();
+ }
const auto &iter = mVolumeGroups.find(volGr);
LOG_ALWAYS_FATAL_IF(iter == std::end(mVolumeGroups), "No volume groups for %s",
toString(stream).c_str());
@@ -260,20 +263,6 @@
return mProductStrategies.getVolumeGroupForStreamType(stream);
}
-StreamTypeVector EngineBase::getStreamTypesForVolumeGroup(volume_group_t volumeGroup) const
-{
- // @TODO default music stream to control volume if no group?
- return (mVolumeGroups.find(volumeGroup) != end(mVolumeGroups)) ?
- mVolumeGroups.at(volumeGroup)->getStreamTypes() :
- StreamTypeVector(AUDIO_STREAM_MUSIC);
-}
-
-AttributesVector EngineBase::getAllAttributesForVolumeGroup(volume_group_t volumeGroup) const
-{
- return (mVolumeGroups.find(volumeGroup) != end(mVolumeGroups)) ?
- mVolumeGroups.at(volumeGroup)->getSupportedAttributes() : AttributesVector();
-}
-
status_t EngineBase::listAudioVolumeGroups(AudioVolumeGroupVector &groups) const
{
for (const auto &iter : mVolumeGroups) {
diff --git a/services/audiopolicy/engine/common/src/ProductStrategy.cpp b/services/audiopolicy/engine/common/src/ProductStrategy.cpp
index 16e6690..f74f190 100644
--- a/services/audiopolicy/engine/common/src/ProductStrategy.cpp
+++ b/services/audiopolicy/engine/common/src/ProductStrategy.cpp
@@ -270,11 +270,7 @@
return group;
}
}
- product_strategy_t defaultStrategy = getDefault();
- if (defaultStrategy == PRODUCT_STRATEGY_NONE) {
- return VOLUME_GROUP_NONE;
- }
- return at(defaultStrategy)->getDefaultVolumeGroup();
+ return getDefaultVolumeGroup();
}
volume_group_t ProductStrategyMap::getVolumeGroupForStreamType(audio_stream_type_t stream) const
@@ -285,6 +281,12 @@
return group;
}
}
+ ALOGW("%s: no volume group for %s, using default", __func__, toString(stream).c_str());
+ return getDefaultVolumeGroup();
+}
+
+volume_group_t ProductStrategyMap::getDefaultVolumeGroup() const
+{
product_strategy_t defaultStrategy = getDefault();
if (defaultStrategy == PRODUCT_STRATEGY_NONE) {
return VOLUME_GROUP_NONE;
diff --git a/services/audiopolicy/engine/config/Android.bp b/services/audiopolicy/engine/config/Android.bp
new file mode 100644
index 0000000..6e72f2a
--- /dev/null
+++ b/services/audiopolicy/engine/config/Android.bp
@@ -0,0 +1,31 @@
+cc_library_static {
+ name: "libaudiopolicyengine_config",
+ export_include_dirs: ["include"],
+ include_dirs: [
+ "external/libxml2/include",
+ "external/icu/icu4c/source/common",
+ ],
+ srcs: [
+ "src/EngineConfig.cpp",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+ shared_libs: [
+ "libmedia_helper",
+ "libandroidicu",
+ "libxml2",
+ "libutils",
+ "liblog",
+ "libcutils",
+ ],
+ static_libs: [
+ "libaudiopolicycomponents",
+ ],
+ header_libs: [
+ "libaudio_system_headers",
+ "libaudiopolicycommon",
+ ],
+}
diff --git a/services/audiopolicy/engine/config/Android.mk b/services/audiopolicy/engine/config/Android.mk
deleted file mode 100644
index 0b292a5..0000000
--- a/services/audiopolicy/engine/config/Android.mk
+++ /dev/null
@@ -1,42 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-##################################################################
-# Component build
-##################################################################
-
-include $(CLEAR_VARS)
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-
-LOCAL_C_INCLUDES := \
- $(LOCAL_EXPORT_C_INCLUDE_DIRS) \
- external/libxml2/include \
- external/icu/icu4c/source/common
-
-LOCAL_SRC_FILES := \
- src/EngineConfig.cpp
-
-LOCAL_CFLAGS += -Wall -Werror -Wextra
-
-LOCAL_SHARED_LIBRARIES := \
- libmedia_helper \
- libandroidicu \
- libxml2 \
- libutils \
- liblog \
- libcutils
-
-LOCAL_STATIC_LIBRARIES := \
- libaudiopolicycomponents
-
-LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
-
-LOCAL_MODULE := libaudiopolicyengineconfig
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_HEADER_LIBRARIES := \
- libaudio_system_headers \
- libaudiopolicycommon
-
-include $(BUILD_SHARED_LIBRARY)
-
diff --git a/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h b/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h
index 38f3401..b7fd031 100644
--- a/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h
+++ b/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h
@@ -169,7 +169,7 @@
* @return selected input device for the audio attributes, may be null if error.
*/
virtual sp<DeviceDescriptor> getInputDeviceForAttributes(
- const audio_attributes_t &attr, AudioMix **mix = nullptr) const = 0;
+ const audio_attributes_t &attr, sp<AudioPolicyMix> *mix = nullptr) const = 0;
/**
* Get the legacy stream type for a given audio attributes.
@@ -283,10 +283,6 @@
*/
virtual volume_group_t getVolumeGroupForStreamType(audio_stream_type_t stream) const = 0;
- virtual StreamTypeVector getStreamTypesForVolumeGroup(volume_group_t volumeGroup) const = 0;
-
- virtual AttributesVector getAllAttributesForVolumeGroup(volume_group_t volumeGroup) const = 0;
-
/**
* @brief listAudioVolumeGroups introspection API to get the Audio Volume Groups, aka
* former stream aliases in Audio Service, defining volume curves attached to one or more
diff --git a/services/audiopolicy/engineconfigurable/Android.mk b/services/audiopolicy/engineconfigurable/Android.mk
index 4eff6e6..84a4422 100644
--- a/services/audiopolicy/engineconfigurable/Android.mk
+++ b/services/audiopolicy/engineconfigurable/Android.mk
@@ -12,10 +12,6 @@
src/EngineInstance.cpp \
src/Stream.cpp \
src/InputSource.cpp \
- ../engine/common/src/VolumeCurve.cpp \
- ../engine/common/src/VolumeGroup.cpp \
- ../engine/common/src/ProductStrategy.cpp \
- ../engine/common/src/EngineBase.cpp
audio_policy_engine_includes_common := \
frameworks/av/services/audiopolicy/engineconfigurable/include \
@@ -37,7 +33,6 @@
LOCAL_HEADER_LIBRARIES := \
libaudiopolicycommon \
- libaudiopolicyengine_common_headers \
libaudiopolicyengine_interface_headers
LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
@@ -47,13 +42,15 @@
LOCAL_STATIC_LIBRARIES := \
libaudiopolicypfwwrapper \
- libaudiopolicycomponents
+ libaudiopolicycomponents \
+ libaudiopolicyengine_common \
+ libaudiopolicyengine_config \
LOCAL_SHARED_LIBRARIES := \
- libaudiopolicyengineconfig \
liblog \
libutils \
liblog \
+ libcutils \
libaudioutils \
libparameter \
libmedia_helper \
diff --git a/services/audiopolicy/engineconfigurable/config/example/Android.mk b/services/audiopolicy/engineconfigurable/config/example/Android.mk
index 45419f0..37271b5 100644
--- a/services/audiopolicy/engineconfigurable/config/example/Android.mk
+++ b/services/audiopolicy/engineconfigurable/config/example/Android.mk
@@ -10,16 +10,15 @@
ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), phone_configurable)
include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_configuration_phone.xml
-LOCAL_MODULE_STEM := audio_policy_engine_configuration.xml
+LOCAL_MODULE := audio_policy_engine_configuration.xml
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := ETC
LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := phone/$(LOCAL_MODULE_STEM)
+LOCAL_SRC_FILES := phone/$(LOCAL_MODULE)
LOCAL_REQUIRED_MODULES := \
- audio_policy_engine_product_strategies_phone.xml \
+ audio_policy_engine_product_strategies.xml \
audio_policy_engine_stream_volumes.xml \
audio_policy_engine_default_stream_volumes.xml \
audio_policy_engine_criteria.xml \
@@ -28,12 +27,11 @@
include $(BUILD_PREBUILT)
include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_product_strategies_phone.xml
-LOCAL_MODULE_STEM := audio_policy_engine_product_strategies.xml
+LOCAL_MODULE := audio_policy_engine_product_strategies.xml
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := ETC
LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := phone/$(LOCAL_MODULE_STEM)
+LOCAL_SRC_FILES := phone/$(LOCAL_MODULE)
include $(BUILD_PREBUILT)
include $(CLEAR_VARS)
@@ -55,39 +53,40 @@
endif # ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), phone_configurable)
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), automotive_configurable)
+ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),automotive_configurable caremu_configurable))
##################################################################
# AUTOMOTIVE CONFIGURATION TOP FILE
##################################################################
include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_configuration_automotive.xml
-LOCAL_MODULE_STEM := audio_policy_engine_configuration.xml
-
+LOCAL_MODULE := audio_policy_engine_configuration.xml
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := ETC
LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := automotive/$(LOCAL_MODULE_STEM)
+LOCAL_SRC_FILES := automotive/$(LOCAL_MODULE)
LOCAL_REQUIRED_MODULES := \
- audio_policy_engine_product_strategies_automotive.xml \
+ audio_policy_engine_product_strategies.xml \
audio_policy_engine_criteria.xml \
audio_policy_engine_criterion_types.xml \
audio_policy_engine_volumes.xml
include $(BUILD_PREBUILT)
+endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),automotive_configurable caremu_configurable))
+
+ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), automotive_configurable)
+
##################################################################
# CONFIGURATION FILES
##################################################################
include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_product_strategies_automotive.xml
-LOCAL_MODULE_STEM := audio_policy_engine_product_strategies.xml
+LOCAL_MODULE := audio_policy_engine_product_strategies.xml
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := ETC
LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := automotive/$(LOCAL_MODULE_STEM)
+LOCAL_SRC_FILES := automotive/$(LOCAL_MODULE)
include $(BUILD_PREBUILT)
include $(CLEAR_VARS)
@@ -100,7 +99,31 @@
endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), automotive_configurable)
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),phone_configurable automotive_configurable))
+ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), caremu_configurable)
+
+##################################################################
+# CONFIGURATION FILES
+##################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := audio_policy_engine_product_strategies.xml
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := ETC
+LOCAL_VENDOR_MODULE := true
+LOCAL_SRC_FILES := caremu/$(LOCAL_MODULE)
+include $(BUILD_PREBUILT)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := audio_policy_engine_volumes.xml
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := ETC
+LOCAL_VENDOR_MODULE := true
+LOCAL_SRC_FILES := caremu/$(LOCAL_MODULE)
+include $(BUILD_PREBUILT)
+
+endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), caremu_configurable)
+
+ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),phone_configurable automotive_configurable caremu_configurable))
include $(CLEAR_VARS)
LOCAL_MODULE := audio_policy_engine_criteria.xml
@@ -123,4 +146,4 @@
include $(PROVISION_CRITERION_TYPES)
-endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),phone_configurable automotive_configurable))
+endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),phone_configurable automotive_configurable caremu_configurable))
diff --git a/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_volumes.xml b/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_volumes.xml
index b326b50..9ec3d77 100644
--- a/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_volumes.xml
+++ b/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_volumes.xml
@@ -159,7 +159,7 @@
<name>phone</name>
<indexMin>1</indexMin>
<indexMax>40</indexMax>
- <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
<point>0,-4200</point>
<point>33,-2800</point>
<point>66,-1400</point>
diff --git a/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_product_strategies.xml b/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_product_strategies.xml
new file mode 100644
index 0000000..c487da9
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_product_strategies.xml
@@ -0,0 +1,170 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Copyright (C) 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.
+-->
+
+<ProductStrategies>
+ <!-- OEM Usages -->
+ <!-- product_strategy will be defined according this order
+ product_strategy is oem_traffic_anouncement if all the conditions are satisfied for
+ AudioAttributes aa
+
+ int type = 0;
+ if (bundle != null) {
+ type = bundle.getInt(KEY_OEM_TYPE, 0);
+ }
+ if(
+ ( aa.mContentType == AudioAttributes.AUDIO_CONTENT_TYPE_SPEECH ) &&
+ ( aa.mUsage == AudioAttributes.AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE ) &&
+ ( type == 1 ) )
+ -->
+
+ <ProductStrategy name="oem_traffic_anouncement">
+ <AttributesGroup volumeGroup="oem_traffic_anouncement">
+ <ContentType value="AUDIO_CONTENT_TYPE_SPEECH"/>
+ <Usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"/>
+ <!-- traffic_annoucement = 1 -->
+ <Bundle key="oem" value="1"/>
+ </AttributesGroup>
+ </ProductStrategy>
+ <ProductStrategy name="oem_strategy_1">
+ <AttributesGroup volumeGroup="oem_adas_2">
+ <ContentType value="AUDIO_CONTENT_TYPE_SPEECH"/>
+ <Usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"/>
+ <Bundle key="oem" value="2"/>
+ </AttributesGroup>
+ </ProductStrategy>
+ <ProductStrategy name="oem_strategy_2">
+ <AttributesGroup volumeGroup="oem_adas_3">
+ <ContentType value="AUDIO_CONTENT_TYPE_SPEECH"/>
+ <Usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"/>
+ <Bundle key="oem" value="3"/>
+ </AttributesGroup>
+ </ProductStrategy>
+
+ <!-- Car Usages -->
+ <!-- Keep those lines only for car -->
+ <!-- Check car conditions if any OEM conditions matched -->
+ <!-- As defined by CarAudioAttributesUtil.java -->
+ <!-- product_strategy will be defined according this order
+ product_strategy is radio if all the conditions are satisfied for AudioAttributes aa
+
+ int type = CAR_AUDIO_TYPE_DEFAULT;
+ if (bundle != null) {
+ type = bundle.getInt(KEY_CAR_AUDIO_TYPE, CAR_AUDIO_TYPE_DEFAULT);
+ }
+ if(
+ ( aa.mContentType == AudioAttributes.AUDIO_CONTENT_TYPE_SPEECH ) &&
+ ( aa.mUsage == AudioAttributes.AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE ) &&
+ ( type == CAR_AUDIO_TYPE_RADIO ) )
+ -->
+ <ProductStrategy name="radio">
+ <AttributesGroup volumeGroup="media_car_audio_type_3">
+ <ContentType value="AUDIO_CONTENT_TYPE_MUSIC"/>
+ <Usage value="AUDIO_USAGE_MEDIA"/>
+ <Bundle key="car_audio_type" value="3"/>
+ </AttributesGroup>
+ </ProductStrategy>
+ <ProductStrategy name="ext_audio_source">
+ <AttributesGroup volumeGroup="media_car_audio_type_7">
+ <ContentType value="AUDIO_CONTENT_TYPE_MUSIC"/>
+ <Usage value="AUDIO_USAGE_MEDIA"/>
+ <Bundle key="car_audio_type" value="7"/>
+ </AttributesGroup>
+ </ProductStrategy>
+ <ProductStrategy name="voice_command">
+ <AttributesGroup volumeGroup="speech">
+ <Attributes>
+ <ContentType value="AUDIO_CONTENT_TYPE_SPEECH"/>
+ <Usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"/>
+ <!-- CAR_AUDIO_TYPE_VOICE_COMMAND = 1 -->
+ <Bundle key="car_audio_type" value="1"/>
+ </Attributes>
+ <Attributes> <Usage value="AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY"/> </Attributes>
+ <Attributes> <Usage value="AUDIO_USAGE_ASSISTANT"/> </Attributes>
+ </AttributesGroup>
+ </ProductStrategy>
+ <ProductStrategy name="safety_alert">
+ <AttributesGroup volumeGroup="system">
+ <ContentType value="AUDIO_CONTENT_TYPE_SONIFICATION"/>
+ <Usage value="AUDIO_USAGE_NOTIFICATION"/>
+ <!-- CAR_AUDIO_TYPE_SAFETY_ALERT = 2 -->
+ <Bundle key="car_audio_type" value="2"/>
+ </AttributesGroup>
+ </ProductStrategy>
+
+ <!-- To be checked
+ CAR_AUDIO_TYPE_CARSERVICE_BOTTOM
+ CAR_AUDIO_TYPE_CARSERVICE_CAR_PROXY
+ CAR_AUDIO_TYPE_CARSERVICE_MEDIA_MUTE
+ -->
+
+ <!-- Generic Usages -->
+ <ProductStrategy name="music">
+ <AttributesGroup streamType="AUDIO_STREAM_MUSIC" volumeGroup="media">
+ <Attributes> <Usage value="AUDIO_USAGE_MEDIA"/> </Attributes>
+ <Attributes> <Usage value="AUDIO_USAGE_GAME"/> </Attributes>
+ <!-- Default product strategy has empty attributes -->
+ <Attributes></Attributes>
+ </AttributesGroup>
+ </ProductStrategy>
+
+ <ProductStrategy name="nav_guidance">
+ <AttributesGroup volumeGroup="speech">
+ <Usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"/>
+ </AttributesGroup>
+ </ProductStrategy>
+ <ProductStrategy name="voice_call">
+ <AttributesGroup streamType="AUDIO_STREAM_VOICE_CALL" volumeGroup="phone">
+ <Attributes> <Usage value="AUDIO_USAGE_VOICE_COMMUNICATION"/> </Attributes>
+ <Attributes> <Usage value="AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING"/> </Attributes>
+ </AttributesGroup>
+ <AttributesGroup streamType="AUDIO_STREAM_BLUETOOTH_SCO" volumeGroup="phone">
+ <Attributes> <Flags value="AUDIO_FLAG_SCO"/> </Attributes>
+ </AttributesGroup>
+ </ProductStrategy>
+ <ProductStrategy name="alarm">
+ <AttributesGroup streamType="AUDIO_STREAM_ALARM" volumeGroup="ring">
+ <Usage value="AUDIO_USAGE_ALARM"/>
+ </AttributesGroup>
+ </ProductStrategy>
+ <ProductStrategy name="ring">
+ <AttributesGroup streamType="AUDIO_STREAM_RING" volumeGroup="ring">
+ <Usage value="AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE"/>
+ </AttributesGroup>
+ </ProductStrategy>
+ <ProductStrategy name="notification">
+ <AttributesGroup streamType="AUDIO_STREAM_NOTIFICATION" volumeGroup="ring">
+ <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION"/> </Attributes>
+ <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT"/> </Attributes>
+ <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED"/> </Attributes>
+ <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST"/> </Attributes>
+ <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION_EVENT"/> </Attributes>
+ </AttributesGroup>
+ </ProductStrategy>
+ <ProductStrategy name="system">
+ <AttributesGroup streamType="AUDIO_STREAM_SYSTEM" volumeGroup="system">
+ <Usage value="AUDIO_USAGE_ASSISTANCE_SONIFICATION"/>
+ </AttributesGroup>
+ </ProductStrategy>
+ <ProductStrategy name="tts">
+ <!-- TTS stream MUST BE MANAGED OUTSIDE default product strategy if NO DEDICATED OUTPUT
+ for TTS, otherwise when beacon happens, default strategy is ... muted.
+ If it is media, it is annoying... -->
+ <AttributesGroup streamType="AUDIO_STREAM_TTS" volumeGroup="tts">
+ <Attributes> <Flags value="AUDIO_FLAG_BEACON"/> </Attributes>
+ </AttributesGroup>
+ </ProductStrategy>
+</ProductStrategies>
+
diff --git a/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_volumes.xml b/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_volumes.xml
new file mode 100644
index 0000000..9ec3d77
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_volumes.xml
@@ -0,0 +1,192 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Copyright (C) 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.
+ -->
+
+<!-- Volume Groups Tables included by Audio Policy Configuration file -->
+<!-- Note:
+ It is VALID to have a group without attributes if a product strategy is following
+ this group for all attributes.
+ Otherwise, attributes must be specified
+-->
+
+<volumeGroups>
+ <volumeGroup>
+ <name>oem_traffic_anouncement</name>
+ <indexMin>0</indexMin>
+ <indexMax>40</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
+ <point>0,-4200</point>
+ <point>33,-2800</point>
+ <point>66,-1400</point>
+ <point>100,0</point>
+ </volume>
+ <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
+ <point>0,-4200</point>
+ <point>33,-2800</point>
+ <point>66,-1400</point>
+ <point>100,0</point>
+ </volume>
+ <volume deviceCategory="DEVICE_CATEGORY_EARPIECE">
+ <point>0,-4200</point>
+ <point>33,-2800</point>
+ <point>66,-1400</point>
+ <point>100,0</point>
+ </volume>
+ <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA">
+ <point>0,-4200</point>
+ <point>33,-2800</point>
+ <point>66,-1400</point>
+ <point>100,0</point>
+ </volume>
+ </volumeGroup>
+
+<!-- OEM ADAS is a volume group that has a single port gain (this is the reason why it is a group
+ but may host different streams.
+ A priority must be given among them (either they are multualy excluisve, so the volume
+ will be the one of the currently acitve stream, otherwise a priority must be given by
+ any mean. -->
+ <volumeGroup>
+ <name>oem_adas_2</name>
+ <indexMin>0</indexMin>
+ <indexMax>40</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
+ <point>0,-4200</point>
+ <point>33,-2800</point>
+ <point>66,-1400</point>
+ <point>100,0</point>
+ </volume>
+ <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
+ <point>0,-4200</point>
+ <point>33,-2800</point>
+ <point>66,-1400</point>
+ <point>100,0</point>
+ </volume>
+ </volumeGroup>
+ <volumeGroup>
+ <name>oem_adas_3</name>
+ <indexMin>0</indexMin>
+ <indexMax>40</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
+ <point>0,-2400</point>
+ <point>33,-1600</point>
+ <point>66,-800</point>
+ <point>100,0</point>
+ </volume>
+ <volume deviceCategory="DEVICE_CATEGORY_EARPIECE">
+ <point>0,-2400</point>
+ <point>33,-1600</point>
+ <point>66,-800</point>
+ <point>100,0</point>
+ </volume>
+ </volumeGroup>
+
+<!-- MEDIA is a volume group that has a single port gain (this is the reason why it is a group
+ but may host different streams.
+ A priority must be given among them (either they are multualy exclusive, so the volume
+ will be the one of the active stream with highest priority (ORDER MATTERS) unless the curves
+ followed will the the curves for the requested attributes.-->
+ <volumeGroup>
+ <name>media_car_audio_type_3</name>
+ <indexMin>0</indexMin>
+ <indexMax>40</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
+ <point>0,-4200</point>
+ <point>33,-2800</point>
+ <point>66,-1400</point>
+ <point>100,0</point>
+ </volume>
+ </volumeGroup>
+ <volumeGroup>
+ <name>media_car_audio_type_7</name>
+ <indexMin>0</indexMin>
+ <indexMax>40</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
+ <point>0,-2400</point>
+ <point>33,-1600</point>
+ <point>66,-800</point>
+ <point>100,0</point>
+ </volume>
+ </volumeGroup>
+ <volumeGroup>
+ <name>media</name>
+ <indexMin>0</indexMin>
+ <indexMax>40</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
+ <point>0,-2400</point>
+ <point>33,-1600</point>
+ <point>66,-800</point>
+ <point>100,0</point>
+ </volume>
+ </volumeGroup>
+
+ <volumeGroup>
+ <name>speech</name>
+ <indexMin>1</indexMin>
+ <indexMax>40</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
+ <point>0,-4200</point>
+ <point>33,-2800</point>
+ <point>66,-1400</point>
+ <point>100,0</point>
+ </volume>
+ </volumeGroup>
+
+ <volumeGroup>
+ <name>system</name>
+ <indexMin>0</indexMin>
+ <indexMax>40</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
+ <point>0,-4200</point>
+ <point>33,-2800</point>
+ <point>66,-1400</point>
+ <point>100,0</point>
+ </volume>
+ </volumeGroup>
+
+ <volumeGroup>
+ <name>phone</name>
+ <indexMin>1</indexMin>
+ <indexMax>40</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
+ <point>0,-4200</point>
+ <point>33,-2800</point>
+ <point>66,-1400</point>
+ <point>100,0</point>
+ </volume>
+ </volumeGroup>
+
+ <volumeGroup>
+ <name>ring</name>
+ <indexMin>0</indexMin>
+ <indexMax>40</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
+ <point>0,-4200</point>
+ <point>33,-2800</point>
+ <point>66,-1400</point>
+ <point>100,0</point>
+ </volume>
+ </volumeGroup>
+
+ <volumeGroup>
+ <name>tts</name>
+ <indexMin>0</indexMin>
+ <indexMax>15</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
+ <point>0,-0</point>
+ <point>100,0</point>
+ </volume>
+ </volumeGroup>
+</volumeGroups>
+
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Android.mk
index 060830b..782fe83 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Android.mk
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Android.mk
@@ -9,7 +9,7 @@
LOCAL_PATH := $(call my-dir)
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),phone_configurable automotive_configurable no-output_configurable no-input_configurable))
+ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),phone_configurable automotive_configurable caremu_configurable no-output_configurable no-input_configurable))
PFW_CORE := external/parameter-framework
#@TODO: upstream new domain generator
@@ -20,6 +20,8 @@
TOOLS := frameworks/av/services/audiopolicy/engineconfigurable/tools
BUILD_PFW_SETTINGS := $(TOOLS)/build_audio_pfw_settings.mk
+PROVISION_STRATEGIES_STRUCTURE := $(TOOLS)/provision_strategies_structure.mk
+
endif
##################################################################
@@ -27,7 +29,7 @@
##################################################################
######### Policy PFW top level file #########
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),phone_configurable automotive_configurable))
+ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),phone_configurable automotive_configurable caremu_configurable))
include $(CLEAR_VARS)
LOCAL_MODULE := ParameterFrameworkConfigurationPolicy.xml
@@ -52,12 +54,27 @@
########## Policy PFW Common Structures #########
include $(CLEAR_VARS)
+LOCAL_MODULE := PolicySubsystem.xml
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := ETC
+LOCAL_VENDOR_MODULE := true
+LOCAL_REQUIRED_MODULES := \
+ PolicySubsystem-CommonTypes.xml \
+ ProductStrategies.xml \
+ PolicySubsystem-Volume.xml \
+ libpolicy-subsystem \
+
+LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Structure/Policy
+LOCAL_SRC_FILES := common/Structure/$(LOCAL_MODULE)
+include $(BUILD_PREBUILT)
+
+include $(CLEAR_VARS)
LOCAL_MODULE := PolicySubsystem-CommonTypes.xml
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := ETC
LOCAL_VENDOR_MODULE := true
LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Structure/Policy
-LOCAL_SRC_FILES := Structure/$(LOCAL_MODULE)
+LOCAL_SRC_FILES := common/Structure/$(LOCAL_MODULE)
include $(BUILD_PREBUILT)
include $(CLEAR_VARS)
@@ -66,16 +83,29 @@
LOCAL_MODULE_CLASS := ETC
LOCAL_VENDOR_MODULE := true
LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Structure/Policy
-LOCAL_SRC_FILES := Structure/$(LOCAL_MODULE)
+LOCAL_SRC_FILES := common/Structure/$(LOCAL_MODULE)
include $(BUILD_PREBUILT)
-endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),phone_configurable automotive_configurable))
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := ProductStrategies.xml
+LOCAL_MODULE_CLASS := ETC
+LOCAL_VENDOR_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Structure/Policy
+LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_configuration.xml
+AUDIO_POLICY_ENGINE_CONFIGURATION_FILE := \
+ $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_configuration.xml
+STRATEGIES_STRUCTURE_FILE := $(LOCAL_PATH)/common/Structure/$(LOCAL_MODULE).in
+
+include $(PROVISION_STRATEGIES_STRUCTURE)
+
+endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),phone_configurable automotive_configurable caremu_configurable))
########## Policy PFW Example Structures #########
ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),no-output_configurable no-input_configurable))
include $(CLEAR_VARS)
-LOCAL_MODULE := PolicySubsystem.xml.common
+LOCAL_MODULE := PolicySubsystem-no-strategy.xml
LOCAL_MODULE_STEM := PolicySubsystem.xml
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := ETC
@@ -86,7 +116,7 @@
libpolicy-subsystem \
LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Structure/Policy
-LOCAL_SRC_FILES := Structure/$(LOCAL_MODULE_STEM)
+LOCAL_SRC_FILES := common/Structure/$(LOCAL_MODULE_STEM)
include $(BUILD_PREBUILT)
endif # ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),no-output_configurable no-input_configurable))
@@ -95,7 +125,7 @@
ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),no-output_configurable)
include $(CLEAR_VARS)
-LOCAL_MODULE := parameter-framework.policy.no-output
+LOCAL_MODULE := parameter-framework.policy
LOCAL_MODULE_STEM := PolicyConfigurableDomains-NoOutputDevice.xml
LOCAL_MODULE_CLASS := ETC
LOCAL_VENDOR_MODULE := true
@@ -103,7 +133,7 @@
LOCAL_REQUIRED_MODULES := \
audio_policy_engine_criteria.xml \
audio_policy_engine_criterion_types.xml \
- PolicySubsystem.xml.common \
+ PolicySubsystem-no-strategy.xml \
PolicyClass.xml \
ParameterFrameworkConfigurationPolicy.xml
@@ -121,7 +151,7 @@
ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),no-input_configurable)
include $(CLEAR_VARS)
-LOCAL_MODULE := parameter-framework.policy.no-input
+LOCAL_MODULE := parameter-framework.policy
LOCAL_MODULE_STEM := PolicyConfigurableDomains-NoInputDevice.xml
LOCAL_MODULE_CLASS := ETC
LOCAL_VENDOR_MODULE := true
@@ -129,7 +159,7 @@
LOCAL_REQUIRED_MODULES := \
audio_policy_engine_criteria.xml \
audio_policy_engine_criterion_types.xml \
- PolicySubsystem.xml.common \
+ PolicySubsystem-no-strategy.xml \
PolicyClass.xml \
ParameterFrameworkConfigurationPolicy.xml
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Android.mk
index ea4a58f..20ca8e2 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Android.mk
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Android.mk
@@ -23,37 +23,9 @@
##################################################################
########## Policy PFW Structures #########
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := PolicySubsystem.xml.car
-LOCAL_MODULE_STEM := PolicySubsystem.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_REQUIRED_MODULES := \
- ProductStrategies.xml.car \
- PolicySubsystem-Volume.xml \
- PolicySubsystem-CommonTypes.xml \
- libpolicy-subsystem
-
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Structure/Policy
-LOCAL_SRC_FILES := Structure/$(LOCAL_MODULE_STEM)
-include $(BUILD_PREBUILT)
-
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := ProductStrategies.xml.car
-LOCAL_MODULE_STEM := ProductStrategies.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Structure/Policy
-LOCAL_SRC_FILES := Structure/$(LOCAL_MODULE_STEM)
-include $(BUILD_PREBUILT)
-
######### Policy PFW Settings #########
include $(CLEAR_VARS)
-LOCAL_MODULE := parameter-framework.policy.car
+LOCAL_MODULE := parameter-framework.policy
LOCAL_MODULE_STEM := PolicyConfigurableDomains.xml
LOCAL_MODULE_CLASS := ETC
LOCAL_VENDOR_MODULE := true
@@ -68,7 +40,7 @@
$(PFW_EDD_FILES)
LOCAL_REQUIRED_MODULES := \
- PolicySubsystem.xml.car \
+ PolicySubsystem.xml \
PolicyClass.xml \
audio_policy_engine_criteria.xml \
audio_policy_engine_criterion_types.xml \
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Settings/device_for_product_strategies.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Settings/device_for_product_strategies.pfw
index 196d82c..57ad592 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Settings/device_for_product_strategies.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Settings/device_for_product_strategies.pfw
@@ -714,4 +714,47 @@
speaker = 0
bus = 0
+ supDomain: Tts
+ domain: UnreachableDevices
+ conf: calibration
+ component: /Policy/policy/product_strategies/tts/selected_output_devices/mask
+ earpiece = 0
+ speaker = 0
+ wired_headset = 0
+ wired_headphone = 0
+ bluetooth_sco = 0
+ bluetooth_sco_headset = 0
+ bluetooth_sco_carkit = 0
+ bluetooth_a2dp = 0
+ bluetooth_a2dp_headphones = 0
+ bluetooth_a2dp_speaker = 0
+ hdmi = 0
+ angl_dock_headset = 0
+ dgtl_dock_headset = 0
+ usb_accessory = 0
+ usb_device = 0
+ remote_submix = 0
+ telephony_tx = 0
+ line = 0
+ hdmi_arc = 0
+ spdif = 0
+ fm = 0
+ aux_line = 0
+ speaker_safe = 0
+ ip = 0
+ proxy = 0
+ usb_headset = 0
+ stub = 0
+ /Policy/policy/product_strategies/tts/device_address = BUS00_MEDIA
+ domain: SelectedDevice
+ conf: Bus
+ AvailableOutputDevices Includes Bus
+ AvailableOutputDevicesAddresses Includes BUS00_MEDIA
+
+ component: /Policy/policy/product_strategies/tts/selected_output_devices/mask
+ bus = 1
+
+ conf: Default
+ component: /Policy/policy/product_strategies/tts/selected_output_devices/mask
+ bus = 0
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Structure/ProductStrategies.xml b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Structure/ProductStrategies.xml
deleted file mode 100644
index 53bba03..0000000
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Structure/ProductStrategies.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 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.
--->
-<ComponentTypeSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:xi="http://www.w3.org/2001/XInclude"
- xsi:noNamespaceSchemaLocation="Schemas/ComponentTypeSet.xsd">
-
- <ComponentType Name="ProductStrategies" Description="">
- <Component Name="oem_traffic_anouncement" Type="ProductStrategy"/>
- <Component Name="oem_strategy_1" Type="ProductStrategy"/>
- <Component Name="oem_strategy_2" Type="ProductStrategy"/>
-
- <Component Name="radio" Type="ProductStrategy"/>
- <Component Name="ext_audio_source" Type="ProductStrategy"/>
- <Component Name="voice_command" Type="ProductStrategy"/>
- <Component Name="safety_alert" Type="ProductStrategy"/>
-
- <Component Name="music" Type="ProductStrategy"/>
- <Component Name="nav_guidance" Type="ProductStrategy"/>
- <Component Name="voice_call" Type="ProductStrategy"/>
- <Component Name="alarm" Type="ProductStrategy"/>
- <Component Name="ring" Type="ProductStrategy"/>
- <Component Name="notification" Type="ProductStrategy"/>
- <Component Name="system" Type="ProductStrategy"/>
- </ComponentType>
-
-</ComponentTypeSet>
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Android.mk
new file mode 100644
index 0000000..8fa8f0a
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Android.mk
@@ -0,0 +1,58 @@
+################################################################################################
+#
+# @NOTE:
+# Audio Policy Engine configurable example for generic device build
+#
+# Any vendor shall have its own configuration within the corresponding device folder
+#
+################################################################################################
+
+ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), caremu_configurable)
+LOCAL_PATH := $(call my-dir)
+
+PFW_CORE := external/parameter-framework
+PFW_DEFAULT_SCHEMAS_DIR := $(PFW_CORE)/upstream/schemas
+PFW_SCHEMAS_DIR := $(PFW_DEFAULT_SCHEMAS_DIR)
+
+TOOLS := frameworks/av/services/audiopolicy/engineconfigurable/tools
+BUILD_PFW_SETTINGS := $(TOOLS)/build_audio_pfw_settings.mk
+
+
+##################################################################
+# CONFIGURATION FILES
+##################################################################
+
+########## Policy PFW Structures #########
+######### Policy PFW Settings #########
+include $(CLEAR_VARS)
+LOCAL_MODULE := parameter-framework.policy
+LOCAL_MODULE_STEM := PolicyConfigurableDomains.xml
+LOCAL_MODULE_CLASS := ETC
+LOCAL_VENDOR_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Settings/Policy
+
+PFW_EDD_FILES := \
+ $(LOCAL_PATH)/Settings/device_for_product_strategies.pfw \
+ $(LOCAL_PATH)/../Settings/device_for_input_source.pfw \
+ $(LOCAL_PATH)/../Settings/volumes.pfw
+
+LOCAL_ADDITIONAL_DEPENDENCIES := \
+ $(PFW_EDD_FILES)
+
+LOCAL_REQUIRED_MODULES := \
+ PolicySubsystem.xml \
+ PolicyClass.xml \
+ audio_policy_engine_criteria.xml \
+ audio_policy_engine_criterion_types.xml \
+ ParameterFrameworkConfigurationPolicy.xml
+
+PFW_CRITERION_TYPES_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criterion_types.xml
+PFW_CRITERIA_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criteria.xml
+
+PFW_TOPLEVEL_FILE := $(TARGET_OUT_VENDOR_ETC)/parameter-framework/ParameterFrameworkConfigurationPolicy.xml
+
+PFW_SCHEMAS_DIR := $(PFW_DEFAULT_SCHEMAS_DIR)
+
+include $(BUILD_PFW_SETTINGS)
+
+endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), caremu_configurable)
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Settings/device_for_product_strategies.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Settings/device_for_product_strategies.pfw
new file mode 100644
index 0000000..ca3464f
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Settings/device_for_product_strategies.pfw
@@ -0,0 +1,690 @@
+supDomain: DeviceForProductStrategies
+ supDomain: OemTrafficAnouncement
+ domain: UnreachableDevices
+ conf: calibration
+ component: /Policy/policy/product_strategies/oem_traffic_anouncement/selected_output_devices/mask
+ earpiece = 0
+ speaker = 0
+ wired_headset = 0
+ wired_headphone = 0
+ bluetooth_sco = 0
+ bluetooth_sco_headset = 0
+ bluetooth_sco_carkit = 0
+ bluetooth_a2dp = 0
+ bluetooth_a2dp_headphones = 0
+ bluetooth_a2dp_speaker = 0
+ hdmi = 0
+ angl_dock_headset = 0
+ dgtl_dock_headset = 0
+ usb_accessory = 0
+ usb_device = 0
+ remote_submix = 0
+ telephony_tx = 0
+ line = 0
+ hdmi_arc = 0
+ spdif = 0
+ fm = 0
+ aux_line = 0
+ speaker_safe = 0
+ ip = 0
+ proxy = 0
+ usb_headset = 0
+ stub = 0
+ /Policy/policy/product_strategies/oem_traffic_anouncement/device_address = BUS00_MEDIA
+
+ domain: SelectedDevice
+ conf: Bus
+ AvailableOutputDevices Includes Bus
+ AvailableOutputDevicesAddresses Includes BUS00_MEDIA
+
+ component: /Policy/policy/product_strategies/oem_traffic_anouncement/selected_output_devices/mask
+ bus = 1
+
+ conf: Default
+ component: /Policy/policy/product_strategies/oem_traffic_anouncement/selected_output_devices/mask
+ bus = 0
+
+ supDomain: OemStrategy1
+ domain: UnreachableDevices
+ conf: calibration
+ component: /Policy/policy/product_strategies/oem_strategy_1/selected_output_devices/mask
+ earpiece = 0
+ speaker = 0
+ wired_headset = 0
+ wired_headphone = 0
+ bluetooth_sco = 0
+ bluetooth_sco_headset = 0
+ bluetooth_sco_carkit = 0
+ bluetooth_a2dp = 0
+ bluetooth_a2dp_headphones = 0
+ bluetooth_a2dp_speaker = 0
+ hdmi = 0
+ angl_dock_headset = 0
+ dgtl_dock_headset = 0
+ usb_accessory = 0
+ usb_device = 0
+ remote_submix = 0
+ telephony_tx = 0
+ line = 0
+ hdmi_arc = 0
+ spdif = 0
+ fm = 0
+ aux_line = 0
+ speaker_safe = 0
+ ip = 0
+ proxy = 0
+ usb_headset = 0
+ stub = 0
+ /Policy/policy/product_strategies/oem_strategy_1/device_address = BUS02_OEM1
+
+ domain: SelectedDevice
+ conf: Bus
+ AvailableOutputDevices Includes Bus
+ AvailableOutputDevicesAddresses Includes BUS02_OEM1
+
+ component: /Policy/policy/product_strategies/oem_strategy_1/selected_output_devices/mask
+ bus = 1
+
+ conf: Default
+ component: /Policy/policy/product_strategies/oem_strategy_1/selected_output_devices/mask
+ bus = 0
+
+
+
+ supDomain: OemStrategy2
+ domain: UnreachableDevices
+ conf: calibration
+ component: /Policy/policy/product_strategies/oem_strategy_2/selected_output_devices/mask
+ earpiece = 0
+ speaker = 0
+ wired_headset = 0
+ wired_headphone = 0
+ bluetooth_sco = 0
+ bluetooth_sco_headset = 0
+ bluetooth_sco_carkit = 0
+ bluetooth_a2dp = 0
+ bluetooth_a2dp_headphones = 0
+ bluetooth_a2dp_speaker = 0
+ hdmi = 0
+ angl_dock_headset = 0
+ dgtl_dock_headset = 0
+ usb_accessory = 0
+ usb_device = 0
+ remote_submix = 0
+ telephony_tx = 0
+ line = 0
+ hdmi_arc = 0
+ spdif = 0
+ fm = 0
+ aux_line = 0
+ speaker_safe = 0
+ ip = 0
+ proxy = 0
+ usb_headset = 0
+ stub = 0
+ /Policy/policy/product_strategies/oem_strategy_2/device_address = BUS01_NAV_GUIDANCE
+
+ domain: SelectedDevice
+ conf: Bus
+ AvailableOutputDevices Includes Bus
+ AvailableOutputDevicesAddresses Includes BUS01_NAV_GUIDANCE
+
+ component: /Policy/policy/product_strategies/oem_strategy_2/selected_output_devices/mask
+ bus = 1
+
+ conf: Default
+ component: /Policy/policy/product_strategies/oem_strategy_2/selected_output_devices/mask
+ bus = 0
+
+
+
+ supDomain: Radio
+ domain: UnreachableDevices
+ conf: calibration
+ component: /Policy/policy/product_strategies/radio/selected_output_devices/mask
+ earpiece = 0
+ speaker = 0
+ wired_headset = 0
+ wired_headphone = 0
+ bluetooth_sco = 0
+ bluetooth_sco_headset = 0
+ bluetooth_sco_carkit = 0
+ bluetooth_a2dp = 0
+ bluetooth_a2dp_headphones = 0
+ bluetooth_a2dp_speaker = 0
+ hdmi = 0
+ angl_dock_headset = 0
+ dgtl_dock_headset = 0
+ usb_accessory = 0
+ usb_device = 0
+ remote_submix = 0
+ telephony_tx = 0
+ line = 0
+ hdmi_arc = 0
+ spdif = 0
+ fm = 0
+ aux_line = 0
+ speaker_safe = 0
+ ip = 0
+ proxy = 0
+ usb_headset = 0
+ stub = 0
+ /Policy/policy/product_strategies/radio/device_address = BUS00_MEDIA
+
+ domain: SelectedDevice
+ conf: Bus
+ AvailableOutputDevices Includes Bus
+ AvailableOutputDevicesAddresses Includes BUS00_MEDIA
+
+ component: /Policy/policy/product_strategies/radio/selected_output_devices/mask
+ bus = 1
+
+ conf: Default
+ component: /Policy/policy/product_strategies/radio/selected_output_devices/mask
+ bus = 0
+
+ supDomain: ExtAudioSource
+ domain: UnreachableDevices
+ conf: calibration
+ component: /Policy/policy/product_strategies/ext_audio_source/selected_output_devices/mask
+ earpiece = 0
+ speaker = 0
+ wired_headset = 0
+ wired_headphone = 0
+ bluetooth_sco = 0
+ bluetooth_sco_headset = 0
+ bluetooth_sco_carkit = 0
+ bluetooth_a2dp = 0
+ bluetooth_a2dp_headphones = 0
+ bluetooth_a2dp_speaker = 0
+ hdmi = 0
+ angl_dock_headset = 0
+ dgtl_dock_headset = 0
+ usb_accessory = 0
+ usb_device = 0
+ remote_submix = 0
+ telephony_tx = 0
+ line = 0
+ hdmi_arc = 0
+ spdif = 0
+ fm = 0
+ aux_line = 0
+ speaker_safe = 0
+ ip = 0
+ proxy = 0
+ usb_headset = 0
+ stub = 0
+ /Policy/policy/product_strategies/ext_audio_source/device_address = BUS00_MEDIA
+
+ domain: SelectedDevice
+ conf: Bus
+ AvailableOutputDevices Includes Bus
+ AvailableOutputDevicesAddresses Includes BUS00_MEDIA
+
+ component: /Policy/policy/product_strategies/ext_audio_source/selected_output_devices/mask
+ bus = 1
+
+ conf: Default
+ component: /Policy/policy/product_strategies/ext_audio_source/selected_output_devices/mask
+ bus = 0
+
+
+
+ supDomain: VoiceCommand
+ domain: UnreachableDevices
+ conf: calibration
+ component: /Policy/policy/product_strategies/voice_command/selected_output_devices/mask
+ earpiece = 0
+ speaker = 0
+ wired_headset = 0
+ wired_headphone = 0
+ bluetooth_sco = 0
+ bluetooth_sco_headset = 0
+ bluetooth_sco_carkit = 0
+ bluetooth_a2dp = 0
+ bluetooth_a2dp_headphones = 0
+ bluetooth_a2dp_speaker = 0
+ hdmi = 0
+ angl_dock_headset = 0
+ dgtl_dock_headset = 0
+ usb_accessory = 0
+ usb_device = 0
+ remote_submix = 0
+ telephony_tx = 0
+ line = 0
+ hdmi_arc = 0
+ spdif = 0
+ fm = 0
+ aux_line = 0
+ speaker_safe = 0
+ ip = 0
+ proxy = 0
+ usb_headset = 0
+ stub = 0
+ /Policy/policy/product_strategies/voice_command/device_address = BUS04_VOICE
+
+ domain: SelectedDevice
+ conf: Bus
+ AvailableOutputDevices Includes Bus
+ AvailableOutputDevicesAddresses Includes BUS04_VOICE
+
+ component: /Policy/policy/product_strategies/voice_command/selected_output_devices/mask
+ bus = 1
+
+ conf: Default
+ component: /Policy/policy/product_strategies/voice_command/selected_output_devices/mask
+ bus = 0
+
+
+ supDomain: SafetyAlert
+ domain: UnreachableDevices
+ conf: calibration
+ component: /Policy/policy/product_strategies/safety_alert/selected_output_devices/mask
+ earpiece = 0
+ speaker = 0
+ wired_headset = 0
+ wired_headphone = 0
+ bluetooth_sco = 0
+ bluetooth_sco_headset = 0
+ bluetooth_sco_carkit = 0
+ bluetooth_a2dp = 0
+ bluetooth_a2dp_headphones = 0
+ bluetooth_a2dp_speaker = 0
+ hdmi = 0
+ angl_dock_headset = 0
+ dgtl_dock_headset = 0
+ usb_accessory = 0
+ usb_device = 0
+ remote_submix = 0
+ telephony_tx = 0
+ line = 0
+ hdmi_arc = 0
+ spdif = 0
+ fm = 0
+ aux_line = 0
+ speaker_safe = 0
+ ip = 0
+ proxy = 0
+ usb_headset = 0
+ stub = 0
+ /Policy/policy/product_strategies/safety_alert/device_address = BUS00_MEDIA
+
+ domain: SelectedDevice
+ conf: Bus
+ AvailableOutputDevices Includes Bus
+ AvailableOutputDevicesAddresses Includes BUS00_MEDIA
+
+ component: /Policy/policy/product_strategies/safety_alert/selected_output_devices/mask
+ bus = 1
+
+ conf: Default
+ component: /Policy/policy/product_strategies/safety_alert/selected_output_devices/mask
+ bus = 0
+
+
+ supDomain: Music
+ domain: UnreachableDevices
+ conf: calibration
+ component: /Policy/policy/product_strategies/music/selected_output_devices/mask
+ earpiece = 0
+ speaker = 0
+ wired_headset = 0
+ wired_headphone = 0
+ bluetooth_sco = 0
+ bluetooth_sco_headset = 0
+ bluetooth_sco_carkit = 0
+ bluetooth_a2dp = 0
+ bluetooth_a2dp_headphones = 0
+ bluetooth_a2dp_speaker = 0
+ hdmi = 0
+ angl_dock_headset = 0
+ dgtl_dock_headset = 0
+ usb_accessory = 0
+ usb_device = 0
+ remote_submix = 0
+ telephony_tx = 0
+ line = 0
+ hdmi_arc = 0
+ spdif = 0
+ fm = 0
+ aux_line = 0
+ speaker_safe = 0
+ ip = 0
+ proxy = 0
+ usb_headset = 0
+ stub = 0
+ /Policy/policy/product_strategies/music/device_address = BUS00_MEDIA
+
+ domain: SelectedDevice
+ conf: Bus
+ AvailableOutputDevices Includes Bus
+ AvailableOutputDevicesAddresses Includes BUS00_MEDIA
+
+ component: /Policy/policy/product_strategies/music/selected_output_devices/mask
+ bus = 1
+
+ conf: Default
+ component: /Policy/policy/product_strategies/music/selected_output_devices/mask
+ bus = 0
+
+
+
+ supDomain: NavGuidance
+ domain: UnreachableDevices
+ conf: calibration
+ component: /Policy/policy/product_strategies/nav_guidance/selected_output_devices/mask
+ earpiece = 0
+ speaker = 0
+ wired_headset = 0
+ wired_headphone = 0
+ bluetooth_sco = 0
+ bluetooth_sco_headset = 0
+ bluetooth_sco_carkit = 0
+ bluetooth_a2dp = 0
+ bluetooth_a2dp_headphones = 0
+ bluetooth_a2dp_speaker = 0
+ hdmi = 0
+ angl_dock_headset = 0
+ dgtl_dock_headset = 0
+ usb_accessory = 0
+ usb_device = 0
+ remote_submix = 0
+ telephony_tx = 0
+ line = 0
+ hdmi_arc = 0
+ spdif = 0
+ fm = 0
+ aux_line = 0
+ speaker_safe = 0
+ ip = 0
+ proxy = 0
+ usb_headset = 0
+ stub = 0
+ /Policy/policy/product_strategies/nav_guidance/device_address = BUS01_NAV_GUIDANCE
+
+ domain: SelectedDevice
+ conf: Bus
+ AvailableOutputDevices Includes Bus
+ AvailableOutputDevicesAddresses Includes BUS01_NAV_GUIDANCE
+
+ component: /Policy/policy/product_strategies/nav_guidance/selected_output_devices/mask
+ bus = 1
+
+ conf: Default
+ component: /Policy/policy/product_strategies/nav_guidance/selected_output_devices/mask
+ bus = 0
+
+
+ supDomain: VoiceCall
+ domain: UnreachableDevices
+ conf: calibration
+ component: /Policy/policy/product_strategies/voice_call/selected_output_devices/mask
+ earpiece = 0
+ speaker = 0
+ wired_headset = 0
+ wired_headphone = 0
+ bluetooth_sco = 0
+ bluetooth_sco_headset = 0
+ bluetooth_sco_carkit = 0
+ bluetooth_a2dp = 0
+ bluetooth_a2dp_headphones = 0
+ bluetooth_a2dp_speaker = 0
+ hdmi = 0
+ angl_dock_headset = 0
+ dgtl_dock_headset = 0
+ usb_accessory = 0
+ usb_device = 0
+ remote_submix = 0
+ telephony_tx = 0
+ line = 0
+ hdmi_arc = 0
+ spdif = 0
+ fm = 0
+ aux_line = 0
+ speaker_safe = 0
+ ip = 0
+ proxy = 0
+ usb_headset = 0
+ stub = 0
+ /Policy/policy/product_strategies/voice_call/device_address = BUS04_VOICE
+
+ domain: SelectedDevice
+ conf: Bus
+ AvailableOutputDevices Includes Bus
+ AvailableOutputDevicesAddresses Includes BUS04_VOICE
+
+ component: /Policy/policy/product_strategies/voice_call/selected_output_devices/mask
+ bus = 1
+
+ conf: Default
+ component: /Policy/policy/product_strategies/voice_call/selected_output_devices/mask
+ bus = 0
+
+
+ supDomain: Alarm
+ domain: UnreachableDevices
+ conf: calibration
+ component: /Policy/policy/product_strategies/alarm/selected_output_devices/mask
+ earpiece = 0
+ speaker = 0
+ wired_headset = 0
+ wired_headphone = 0
+ bluetooth_sco = 0
+ bluetooth_sco_headset = 0
+ bluetooth_sco_carkit = 0
+ bluetooth_a2dp = 0
+ bluetooth_a2dp_headphones = 0
+ bluetooth_a2dp_speaker = 0
+ hdmi = 0
+ angl_dock_headset = 0
+ dgtl_dock_headset = 0
+ usb_accessory = 0
+ usb_device = 0
+ remote_submix = 0
+ telephony_tx = 0
+ line = 0
+ hdmi_arc = 0
+ spdif = 0
+ fm = 0
+ aux_line = 0
+ speaker_safe = 0
+ ip = 0
+ proxy = 0
+ usb_headset = 0
+ stub = 0
+ /Policy/policy/product_strategies/alarm/device_address = BUS00_MEDIA
+
+ domain: SelectedDevice
+ conf: Bus
+ AvailableOutputDevices Includes Bus
+ AvailableOutputDevicesAddresses Includes BUS00_MEDIA
+
+ component: /Policy/policy/product_strategies/alarm/selected_output_devices/mask
+ bus = 1
+
+ conf: Default
+ component: /Policy/policy/product_strategies/alarm/selected_output_devices/mask
+ bus = 0
+
+
+ supDomain: Ring
+ domain: UnreachableDevices
+ conf: calibration
+ component: /Policy/policy/product_strategies/ring/selected_output_devices/mask
+ earpiece = 0
+ speaker = 0
+ wired_headset = 0
+ wired_headphone = 0
+ bluetooth_sco = 0
+ bluetooth_sco_headset = 0
+ bluetooth_sco_carkit = 0
+ bluetooth_a2dp = 0
+ bluetooth_a2dp_headphones = 0
+ bluetooth_a2dp_speaker = 0
+ hdmi = 0
+ angl_dock_headset = 0
+ dgtl_dock_headset = 0
+ usb_accessory = 0
+ usb_device = 0
+ remote_submix = 0
+ telephony_tx = 0
+ line = 0
+ hdmi_arc = 0
+ spdif = 0
+ fm = 0
+ aux_line = 0
+ speaker_safe = 0
+ ip = 0
+ proxy = 0
+ usb_headset = 0
+ stub = 0
+ /Policy/policy/product_strategies/ring/device_address = BUS04_VOICE
+
+ domain: SelectedDevice
+ conf: Bus
+ AvailableOutputDevices Includes Bus
+ AvailableOutputDevicesAddresses Includes BUS04_VOICE
+
+ component: /Policy/policy/product_strategies/ring/selected_output_devices/mask
+ bus = 1
+
+ conf: Default
+ component: /Policy/policy/product_strategies/ring/selected_output_devices/mask
+ bus = 0
+
+
+ supDomain: Notification
+ domain: UnreachableDevices
+ conf: calibration
+ component: /Policy/policy/product_strategies/notification/selected_output_devices/mask
+ earpiece = 0
+ speaker = 0
+ wired_headset = 0
+ wired_headphone = 0
+ bluetooth_sco = 0
+ bluetooth_sco_headset = 0
+ bluetooth_sco_carkit = 0
+ bluetooth_a2dp = 0
+ bluetooth_a2dp_headphones = 0
+ bluetooth_a2dp_speaker = 0
+ hdmi = 0
+ angl_dock_headset = 0
+ dgtl_dock_headset = 0
+ usb_accessory = 0
+ usb_device = 0
+ remote_submix = 0
+ telephony_tx = 0
+ line = 0
+ hdmi_arc = 0
+ spdif = 0
+ fm = 0
+ aux_line = 0
+ speaker_safe = 0
+ ip = 0
+ proxy = 0
+ usb_headset = 0
+ stub = 0
+ /Policy/policy/product_strategies/notification/device_address = BUS00_MEDIA
+
+ domain: SelectedDevice
+ conf: Bus
+ AvailableOutputDevices Includes Bus
+ AvailableOutputDevicesAddresses Includes BUS00_MEDIA
+
+ component: /Policy/policy/product_strategies/notification/selected_output_devices/mask
+ bus = 1
+
+ conf: Default
+ component: /Policy/policy/product_strategies/notification/selected_output_devices/mask
+ bus = 0
+
+
+ supDomain: System
+ domain: UnreachableDevices
+ conf: calibration
+ component: /Policy/policy/product_strategies/system/selected_output_devices/mask
+ earpiece = 0
+ speaker = 0
+ wired_headset = 0
+ wired_headphone = 0
+ bluetooth_sco = 0
+ bluetooth_sco_headset = 0
+ bluetooth_sco_carkit = 0
+ bluetooth_a2dp = 0
+ bluetooth_a2dp_headphones = 0
+ bluetooth_a2dp_speaker = 0
+ hdmi = 0
+ angl_dock_headset = 0
+ dgtl_dock_headset = 0
+ usb_accessory = 0
+ usb_device = 0
+ remote_submix = 0
+ telephony_tx = 0
+ line = 0
+ hdmi_arc = 0
+ spdif = 0
+ fm = 0
+ aux_line = 0
+ speaker_safe = 0
+ ip = 0
+ proxy = 0
+ usb_headset = 0
+ stub = 0
+ /Policy/policy/product_strategies/system/device_address = BUS03_SYSTEM_SOUND
+
+ domain: SelectedDevice
+ conf: Bus
+ AvailableOutputDevices Includes Bus
+ AvailableOutputDevicesAddresses Includes BUS03_SYSTEM_SOUND
+
+ component: /Policy/policy/product_strategies/system/selected_output_devices/mask
+ bus = 1
+
+ conf: Default
+ component: /Policy/policy/product_strategies/system/selected_output_devices/mask
+ bus = 0
+
+ supDomain: Tts
+ domain: UnreachableDevices
+ conf: calibration
+ component: /Policy/policy/product_strategies/tts/selected_output_devices/mask
+ earpiece = 0
+ speaker = 0
+ wired_headset = 0
+ wired_headphone = 0
+ bluetooth_sco = 0
+ bluetooth_sco_headset = 0
+ bluetooth_sco_carkit = 0
+ bluetooth_a2dp = 0
+ bluetooth_a2dp_headphones = 0
+ bluetooth_a2dp_speaker = 0
+ hdmi = 0
+ angl_dock_headset = 0
+ dgtl_dock_headset = 0
+ usb_accessory = 0
+ usb_device = 0
+ remote_submix = 0
+ telephony_tx = 0
+ line = 0
+ hdmi_arc = 0
+ spdif = 0
+ fm = 0
+ aux_line = 0
+ speaker_safe = 0
+ ip = 0
+ proxy = 0
+ usb_headset = 0
+ stub = 0
+ /Policy/policy/product_strategies/tts/device_address = BUS00_MEDIA
+
+ domain: SelectedDevice
+ conf: Bus
+ AvailableOutputDevices Includes Bus
+ AvailableOutputDevicesAddresses Includes BUS00_MEDIA
+
+ component: /Policy/policy/product_strategies/tts/selected_output_devices/mask
+ bus = 1
+
+ conf: Default
+ component: /Policy/policy/product_strategies/tts/selected_output_devices/mask
+ bus = 0
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Android.mk
index e9d67e9..d1845b8 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Android.mk
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Android.mk
@@ -22,37 +22,9 @@
# CONFIGURATION FILES
##################################################################
########## Policy PFW Structures #########
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := PolicySubsystem.xml.phone
-LOCAL_MODULE_STEM := PolicySubsystem.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_REQUIRED_MODULES := \
- PolicySubsystem-CommonTypes.xml \
- ProductStrategies.xml.phone \
- PolicySubsystem-Volume.xml \
- libpolicy-subsystem \
-
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Structure/Policy
-LOCAL_SRC_FILES := Structure/$(LOCAL_MODULE_STEM)
-include $(BUILD_PREBUILT)
-
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := ProductStrategies.xml.phone
-LOCAL_MODULE_STEM := ProductStrategies.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Structure/Policy
-LOCAL_SRC_FILES := Structure/$(LOCAL_MODULE_STEM)
-include $(BUILD_PREBUILT)
-
######### Policy PFW Settings #########
include $(CLEAR_VARS)
-LOCAL_MODULE := parameter-framework.policy.phone
+LOCAL_MODULE := parameter-framework.policy
LOCAL_MODULE_STEM := PolicyConfigurableDomains.xml
LOCAL_MODULE_CLASS := ETC
LOCAL_VENDOR_MODULE := true
@@ -68,15 +40,15 @@
$(LOCAL_PATH)/Settings/device_for_product_strategy_phone.pfw \
$(LOCAL_PATH)/Settings/device_for_product_strategy_sonification.pfw \
$(LOCAL_PATH)/Settings/device_for_product_strategy_sonification_respectful.pfw \
- $(LOCAL_PATH)/Settings/device_for_product_strategy_rerouting.pfw \
$(LOCAL_PATH)/Settings/device_for_product_strategy_transmitted_through_speaker.pfw \
- $(LOCAL_PATH)/Settings/device_for_product_strategy_unknown.pfw
+ $(LOCAL_PATH)/Settings/device_for_product_strategy_rerouting.pfw \
+ $(LOCAL_PATH)/Settings/device_for_product_strategy_patch.pfw
LOCAL_ADDITIONAL_DEPENDENCIES := \
$(PFW_EDD_FILES)
LOCAL_REQUIRED_MODULES := \
- PolicySubsystem.xml.phone \
+ PolicySubsystem.xml \
PolicyClass.xml \
audio_policy_engine_criteria.xml \
audio_policy_engine_criterion_types.xml \
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_unknown.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_patch.pfw
similarity index 79%
rename from services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_unknown.pfw
rename to services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_patch.pfw
index c46cf56..d2cc090 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_unknown.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_patch.pfw
@@ -1,8 +1,8 @@
supDomain: DeviceForProductStrategy
- supDomain: Unknown
+ supDomain: Patch
domain: UnreachableDevices
conf: calibration
- component: /Policy/policy/product_strategies/unknown/selected_output_devices/mask
+ component: /Policy/policy/product_strategies/patch/selected_output_devices/mask
earpiece = 0
speaker = 0
wired_headset = 0
@@ -31,6 +31,6 @@
usb_headset = 0
bus = 0
stub = 0
- /Policy/policy/product_strategies/unknown/device_address =
+ /Policy/policy/product_strategies/patch/device_address =
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_rerouting.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_rerouting.pfw
index c064c18..10f8814 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_rerouting.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_rerouting.pfw
@@ -29,15 +29,8 @@
ip = 0
proxy = 0
usb_headset = 0
+ bus = 0
stub = 0
/Policy/policy/product_strategies/rerouting/device_address =
- domain: SelectedDevice
- conf: Bus
- component: /Policy/policy/product_strategies/rerouting/selected_output_devices/mask
- bus = 1
-
- conf: Default
- component: /Policy/policy/product_strategies/rerouting/selected_output_devices/mask
- bus = 0
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Structure/PolicySubsystem.xml b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Structure/PolicySubsystem.xml
deleted file mode 100644
index b55ce2c..0000000
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Structure/PolicySubsystem.xml
+++ /dev/null
@@ -1,88 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 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.
--->
-<Subsystem xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:xi="http://www.w3.org/2001/XInclude"
- xsi:noNamespaceSchemaLocation="Schemas/Subsystem.xsd"
- Name="policy" Type="Policy">
-
- <ComponentLibrary>
- <!--#################### GLOBAL COMPONENTS BEGIN ####################-->
- <!-- Common Types defintion -->
- <xi:include href="PolicySubsystem-CommonTypes.xml"/>
- <xi:include href="ProductStrategies.xml"/>
-
-
- <!--#################### GLOBAL COMPONENTS END ####################-->
-
- <!--#################### STREAM BEGIN ####################-->
-
- <ComponentType Name="Streams" Description="associated to audio_stream_type_t definition">
- <Component Name="voice_call" Type="Stream" Mapping="Name:AUDIO_STREAM_VOICE_CALL"/>
- <Component Name="system" Type="Stream" Mapping="Name:AUDIO_STREAM_SYSTEM"/>
- <Component Name="ring" Type="Stream" Mapping="Name:AUDIO_STREAM_RING"/>
- <Component Name="music" Type="Stream" Mapping="Name:AUDIO_STREAM_MUSIC"/>
- <Component Name="alarm" Type="Stream" Mapping="Name:AUDIO_STREAM_ALARM"/>
- <Component Name="notification" Type="Stream" Mapping="Name:AUDIO_STREAM_NOTIFICATION"/>
- <Component Name="bluetooth_sco" Type="Stream" Mapping="Name:AUDIO_STREAM_BLUETOOTH_SCO"/>
- <Component Name="enforced_audible" Type="Stream" Mapping="Name:AUDIO_STREAM_ENFORCED_AUDIBLE"
- Description="Sounds that cannot be muted by user and must be routed to speaker"/>
- <Component Name="dtmf" Type="Stream" Mapping="Name:AUDIO_STREAM_DTMF"/>
- <Component Name="tts" Type="Stream" Mapping="Name:AUDIO_STREAM_TTS"
- Description="Transmitted Through Speaker. Plays over speaker only, silent on other devices"/>
- <Component Name="accessibility" Type="Stream" Mapping="Name:AUDIO_STREAM_ACCESSIBILITY"
- Description="For accessibility talk back prompts"/>
- <Component Name="rerouting" Type="Stream" Mapping="Name:AUDIO_STREAM_REROUTING"
- Description="For dynamic policy output mixes"/>
- <Component Name="patch" Type="Stream" Mapping="Name:AUDIO_STREAM_PATCH"
- Description="For internal audio flinger tracks. Fixed volume"/>
- </ComponentType>
-
- <!--#################### STREAM END ####################-->
-
- <!--#################### INPUT SOURCE BEGIN ####################-->
-
- <ComponentType Name="InputSources" Description="associated to audio_source_t definition,
- identifier mapping must match the value of the enum">
- <Component Name="default" Type="InputSource" Mapping="Name:AUDIO_SOURCE_DEFAULT"/>
- <Component Name="mic" Type="InputSource" Mapping="Name:AUDIO_SOURCE_MIC"/>
- <Component Name="voice_uplink" Type="InputSource"
- Mapping="Name:AUDIO_SOURCE_VOICE_UPLINK"/>
- <Component Name="voice_downlink" Type="InputSource"
- Mapping="Name:AUDIO_SOURCE_VOICE_DOWNLINK"/>
- <Component Name="voice_call" Type="InputSource"
- Mapping="Name:AUDIO_SOURCE_VOICE_CALL"/>
- <Component Name="camcorder" Type="InputSource" Mapping="Name:AUDIO_SOURCE_CAMCORDER"/>
- <Component Name="voice_recognition" Type="InputSource"
- Mapping="Name:AUDIO_SOURCE_VOICE_RECOGNITION"/>
- <Component Name="voice_communication" Type="InputSource"
- Mapping="Name:AUDIO_SOURCE_VOICE_COMMUNICATION"/>
- <Component Name="remote_submix" Type="InputSource"
- Mapping="Name:AUDIO_SOURCE_REMOTE_SUBMIX"/>
- <Component Name="unprocessed" Type="InputSource"
- Mapping="Name:AUDIO_SOURCE_UNPROCESSED"/>
- <Component Name="fm_tuner" Type="InputSource" Mapping="Name:AUDIO_SOURCE_FM_TUNER"/>
- <Component Name="hotword" Type="InputSource" Mapping="Name:AUDIO_SOURCE_HOTWORD"/>
- </ComponentType>
-
- <!--#################### INPUT SOURCE END ####################-->
- </ComponentLibrary>
-
- <InstanceDefinition>
- <Component Name="streams" Type="Streams"/>
- <Component Name="input_sources" Type="InputSources"/>
- <Component Name="product_strategies" Type="ProductStrategies"/>
- </InstanceDefinition>
-</Subsystem>
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Structure/ProductStrategies.xml b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Structure/ProductStrategies.xml
deleted file mode 100644
index 4cbb3da..0000000
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Structure/ProductStrategies.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 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.
--->
-<ComponentTypeSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:xi="http://www.w3.org/2001/XInclude"
- xsi:noNamespaceSchemaLocation="Schemas/ComponentTypeSet.xsd">
-
- <ComponentType Name="ProductStrategies" Description="">
- <Component Name="accessibility" Type="ProductStrategy"/>
- <Component Name="enforced_audible" Type="ProductStrategy"/>
- <Component Name="transmitted_through_speaker" Type="ProductStrategy"/>
-
- <Component Name="media" Type="ProductStrategy"/>
- <Component Name="phone" Type="ProductStrategy"/>
- <Component Name="dtmf" Type="ProductStrategy"/>
-
- <Component Name="sonification" Type="ProductStrategy"/>
- <Component Name="sonification_respectful" Type="ProductStrategy"/>
- <Component Name="rerouting" Type="ProductStrategy"/>
- <Component Name="unknown" Type="ProductStrategy"/>
- </ComponentType>
-
-</ComponentTypeSet>
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Structure/PolicyClass.xml b/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicyClass.xml
similarity index 100%
rename from services/audiopolicy/engineconfigurable/parameter-framework/examples/Structure/PolicyClass.xml
rename to services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicyClass.xml
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Structure/PolicySubsystem-CommonTypes.xml b/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem-CommonTypes.xml
similarity index 100%
rename from services/audiopolicy/engineconfigurable/parameter-framework/examples/Structure/PolicySubsystem-CommonTypes.xml
rename to services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem-CommonTypes.xml
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Structure/PolicySubsystem.xml b/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem-no-strategy.xml
similarity index 100%
rename from services/audiopolicy/engineconfigurable/parameter-framework/examples/Structure/PolicySubsystem.xml
rename to services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem-no-strategy.xml
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Structure/PolicySubsystem.xml b/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem.xml
similarity index 100%
rename from services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Structure/PolicySubsystem.xml
rename to services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem.xml
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/ProductStrategies.xml.in b/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/ProductStrategies.xml.in
new file mode 100644
index 0000000..2760b25
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/ProductStrategies.xml.in
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+<ComponentTypeSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ xsi:noNamespaceSchemaLocation="Schemas/ComponentTypeSet.xsd">
+
+ <!-- automatically populate the strategy structure plugin file from Engine Configuration XML file
+ Component Name="xxx" Type="ProductStrategy"/-->
+ <ComponentType Name="ProductStrategies" Description="">
+ </ComponentType>
+
+</ComponentTypeSet>
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk
index 65dc9af..4706d7d 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk
@@ -36,7 +36,9 @@
LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
-LOCAL_STATIC_LIBRARIES := libpfw_utility
+LOCAL_STATIC_LIBRARIES := \
+ libpfw_utility \
+ libaudiopolicycomponents
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := libpolicy-subsystem
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/PolicySubsystem.cpp b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/PolicySubsystem.cpp
index bfc1bca..8bd7f66 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/PolicySubsystem.cpp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/PolicySubsystem.cpp
@@ -72,7 +72,7 @@
);
addSubsystemObjectFactory(
new TSubsystemObjectFactory<ProductStrategy>(
- mProductStrategyComponentName, 0)
+ mProductStrategyComponentName, (1 << MappingKeyName))
);
}
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/ProductStrategy.cpp b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/ProductStrategy.cpp
index bb29ef1..ebd9456 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/ProductStrategy.cpp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/ProductStrategy.cpp
@@ -32,6 +32,8 @@
(MappingKeyAmendEnd - MappingKeyAmend1 + 1),
context)
{
+ std::string name(context.getItem(MappingKeyName));
+
ALOG_ASSERT(instanceConfigurableElement != nullptr, "Invalid Configurable Element");
mPolicySubsystem = static_cast<const PolicySubsystem *>(
instanceConfigurableElement->getBelongingSubsystem());
@@ -40,7 +42,6 @@
mPolicyPluginInterface = mPolicySubsystem->getPolicyPluginInterface();
ALOG_ASSERT(mPolicyPluginInterface != nullptr, "Invalid Policy Plugin Interface");
- std::string name(instanceConfigurableElement->getName());
mId = mPolicyPluginInterface->getProductStrategyByName(name);
ALOG_ASSERT(mId != PRODUCT_STRATEGY_INVALID, "Product Strategy %s not found", name.c_str());
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.cpp b/services/audiopolicy/engineconfigurable/src/Engine.cpp
index 89a1694..89aaa84 100644
--- a/services/audiopolicy/engineconfigurable/src/Engine.cpp
+++ b/services/audiopolicy/engineconfigurable/src/Engine.cpp
@@ -295,7 +295,7 @@
}
sp<DeviceDescriptor> Engine::getInputDeviceForAttributes(const audio_attributes_t &attr,
- AudioMix **mix) const
+ sp<AudioPolicyMix> *mix) const
{
const auto &policyMixes = getApmObserver()->getAudioPolicyMixCollection();
const auto &availableInputDevices = getApmObserver()->getAvailableInputDevices();
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.h b/services/audiopolicy/engineconfigurable/src/Engine.h
index 5553994..4662e7e 100644
--- a/services/audiopolicy/engineconfigurable/src/Engine.h
+++ b/services/audiopolicy/engineconfigurable/src/Engine.h
@@ -62,7 +62,7 @@
bool fromCache = false) const override;
sp<DeviceDescriptor> getInputDeviceForAttributes(
- const audio_attributes_t &attr, AudioMix **mix = nullptr) const override;
+ const audio_attributes_t &attr, sp<AudioPolicyMix> *mix = nullptr) const override;
void updateDeviceSelectionCache() override;
diff --git a/services/audiopolicy/engineconfigurable/tools/Android.bp b/services/audiopolicy/engineconfigurable/tools/Android.bp
index d8f29dc..8c16972 100644
--- a/services/audiopolicy/engineconfigurable/tools/Android.bp
+++ b/services/audiopolicy/engineconfigurable/tools/Android.bp
@@ -12,13 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-python_binary_host {
- name: "buildPolicyCriterionTypes.py",
- owner: "renault",
- main: "buildPolicyCriterionTypes.py",
- srcs: [
- "buildPolicyCriterionTypes.py",
- ],
+python_defaults {
+ name: "tools_default",
version: {
py2: {
enabled: true,
@@ -29,3 +24,37 @@
},
}
+python_binary_host {
+ name: "buildPolicyCriterionTypes.py",
+ main: "buildPolicyCriterionTypes.py",
+ srcs: [
+ "buildPolicyCriterionTypes.py",
+ ],
+ defaults: ["tools_default"],
+}
+
+python_binary_host {
+ name: "domainGeneratorPolicy.py",
+ main: "domainGeneratorPolicy.py",
+ srcs: [
+ "domainGeneratorPolicy.py",
+ ],
+ defaults: ["tools_default"],
+ libs: [
+ "EddParser.py",
+ "hostConfig.py",
+ "PFWScriptGenerator.py",
+ ],
+ required: [
+ "domainGeneratorConnector",
+ ],
+}
+
+python_binary_host {
+ name: "buildStrategiesStructureFile.py",
+ main: "buildStrategiesStructureFile.py",
+ srcs: [
+ "buildStrategiesStructureFile.py",
+ ],
+ defaults: ["tools_default"],
+}
diff --git a/services/audiopolicy/engineconfigurable/tools/buildStrategiesStructureFile.py b/services/audiopolicy/engineconfigurable/tools/buildStrategiesStructureFile.py
new file mode 100755
index 0000000..ee70b26
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/tools/buildStrategiesStructureFile.py
@@ -0,0 +1,139 @@
+#!/usr/bin/python
+
+#
+# Copyright 2019, 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.
+#
+
+import argparse
+import re
+import sys
+import tempfile
+import os
+import logging
+import subprocess
+import xml.etree.ElementTree as ET
+import xml.etree.ElementInclude as EI
+import xml.dom.minidom as MINIDOM
+from collections import OrderedDict
+
+#
+# Helper script that helps to feed at build time the XML Product Strategies Structure file file used
+# by the engineconfigurable to start the parameter-framework.
+# It prevents to fill them manually and avoid divergences with android.
+#
+# The Product Strategies Structure file is fed from the audio policy engine configuration file
+# in order to discover all the strategies available for the current platform.
+# --audiopolicyengineconfigurationfile <path/to/audio_policy_engine_configuration.xml>
+#
+# The reference file of ProductStrategies structure must also be set as an input of the script:
+# --productstrategiesstructurefile <path/to/structure/file/ProductStrategies.xml.in>
+#
+# At last, the output of the script shall be set also:
+# --outputfile <path/to/out/<system|vendor|odm>/etc/ProductStrategies.xml>
+#
+
+def parseArgs():
+ argparser = argparse.ArgumentParser(description="Parameter-Framework XML \
+ product strategies structure file generator.\n\
+ Exit with the number of (recoverable or not) error that occured.")
+ argparser.add_argument('--audiopolicyengineconfigurationfile',
+ help="Android Audio Policy Engine Configuration file, Mandatory.",
+ metavar="(AUDIO_POLICY_ENGINE_CONFIGURATION_FILE)",
+ type=argparse.FileType('r'),
+ required=True)
+ argparser.add_argument('--productstrategiesstructurefile',
+ help="Product Strategies Structure XML base file, Mandatory.",
+ metavar="STRATEGIES_STRUCTURE_FILE",
+ type=argparse.FileType('r'),
+ required=True)
+ argparser.add_argument('--outputfile',
+ help="Product Strategies Structure output file, Mandatory.",
+ metavar="STRATEGIES_STRUCTURE_OUTPUT_FILE",
+ type=argparse.FileType('w'),
+ required=True)
+ argparser.add_argument('--verbose',
+ action='store_true')
+
+ return argparser.parse_args()
+
+
+def generateXmlStructureFile(strategies, strategyStructureInFile, outputFile):
+
+ logging.info("Importing strategyStructureInFile {}".format(strategyStructureInFile))
+ strategies_in_tree = ET.parse(strategyStructureInFile)
+
+ strategies_root = strategies_in_tree.getroot()
+ strategy_components = strategies_root.find('ComponentType')
+
+ for strategy_name in strategies:
+ context_mapping = "".join(map(str, ["Name:", strategy_name]))
+ strategy_pfw_name = strategy_name.replace('STRATEGY_', '').lower()
+ strategy_component_node = ET.SubElement(strategy_components, "Component", Name=strategy_pfw_name, Type="ProductStrategy", Mapping=context_mapping)
+
+ xmlstr = ET.tostring(strategies_root, encoding='utf8', method='xml')
+ reparsed = MINIDOM.parseString(xmlstr)
+ prettyXmlStr = reparsed.toprettyxml(newl='\r\n')
+ prettyXmlStr = os.linesep.join([s for s in prettyXmlStr.splitlines() if s.strip()])
+ outputFile.write(prettyXmlStr.encode('utf-8'))
+
+def capitalizeLine(line):
+ return ' '.join((w.capitalize() for w in line.split(' ')))
+
+
+#
+# Parse the audio policy configuration file and output a dictionary of device criteria addresses
+#
+def parseAndroidAudioPolicyEngineConfigurationFile(audiopolicyengineconfigurationfile):
+
+ logging.info("Checking Audio Policy Engine Configuration file {}".format(audiopolicyengineconfigurationfile))
+ #
+ # extract all product strategies name from audio policy engine configuration file
+ #
+ strategy_names = []
+
+ oldWorkingDir = os.getcwd()
+ print "Current working directory %s" % oldWorkingDir
+
+ newDir = os.path.join(oldWorkingDir , audiopolicyengineconfigurationfile.name)
+
+ policy_engine_in_tree = ET.parse(audiopolicyengineconfigurationfile)
+ os.chdir(os.path.dirname(os.path.normpath(newDir)))
+
+ print "new working directory %s" % os.getcwd()
+
+ policy_engine_root = policy_engine_in_tree.getroot()
+ EI.include(policy_engine_root)
+
+ os.chdir(oldWorkingDir)
+
+ for strategy in policy_engine_root.iter('ProductStrategy'):
+ strategy_names.append(strategy.get('name'))
+
+ return strategy_names
+
+
+def main():
+ logging.root.setLevel(logging.INFO)
+ args = parseArgs()
+
+ strategies = parseAndroidAudioPolicyEngineConfigurationFile(args.audiopolicyengineconfigurationfile)
+
+ product_strategies_structure = args.productstrategiesstructurefile
+
+ generateXmlStructureFile(strategies, product_strategies_structure, args.outputfile)
+
+# If this file is directly executed
+if __name__ == "__main__":
+ exit(main())
diff --git a/services/audiopolicy/engineconfigurable/tools/provision_strategies_structure.mk b/services/audiopolicy/engineconfigurable/tools/provision_strategies_structure.mk
new file mode 100644
index 0000000..72c938c
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/tools/provision_strategies_structure.mk
@@ -0,0 +1,21 @@
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SYSTEM)/base_rules.mk
+
+$(LOCAL_BUILT_MODULE): MY_STRATEGIES_STRUCTURE_FILE := $(STRATEGIES_STRUCTURE_FILE)
+$(LOCAL_BUILT_MODULE): MY_AUDIO_POLICY_ENGINE_CONFIGURATION_FILE := $(AUDIO_POLICY_ENGINE_CONFIGURATION_FILE)
+$(LOCAL_BUILT_MODULE): MY_PROVISION_TOOL := $(HOST_OUT)/bin/buildStrategiesStructureFile.py
+$(LOCAL_BUILT_MODULE): $(LOCAL_REQUIRED_MODULES) $(LOCAL_ADDITIONAL_DEPENDENCIES) \
+ buildStrategiesStructureFile.py \
+ $(STRATEGIES_STRUCTURE_FILE) \
+ $(AUDIO_POLICY_ENGINE_CONFIGURATION_FILE)
+
+ "$(MY_PROVISION_TOOL)" \
+ --audiopolicyengineconfigurationfile "$(MY_AUDIO_POLICY_ENGINE_CONFIGURATION_FILE)" \
+ --productstrategiesstructurefile "$(MY_STRATEGIES_STRUCTURE_FILE)" \
+ --outputfile "$(@)"
+
+# Clear variables for further use
+STRATEGIES_STRUCTURE_FILE :=
+AUDIO_POLICY_ENGINE_CONFIGURATION_FILE :=
diff --git a/services/audiopolicy/enginedefault/Android.bp b/services/audiopolicy/enginedefault/Android.bp
new file mode 100644
index 0000000..7b42c6a
--- /dev/null
+++ b/services/audiopolicy/enginedefault/Android.bp
@@ -0,0 +1,32 @@
+cc_library_shared {
+ name: "libaudiopolicyenginedefault",
+ export_include_dirs: ["include"],
+ srcs: [
+ "src/Engine.cpp",
+ "src/EngineInstance.cpp",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+ local_include_dirs: ["include"],
+ header_libs: [
+ "libbase_headers",
+ "libaudiopolicycommon",
+ "libaudiopolicyengine_interface_headers",
+ ],
+ static_libs: [
+ "libaudiopolicycomponents",
+ "libaudiopolicyengine_common",
+ "libaudiopolicyengine_config",
+ ],
+ shared_libs: [
+ "liblog",
+ "libcutils",
+ "libutils",
+ "libmedia_helper",
+ "libaudiopolicy",
+ "libxml2",
+ ],
+}
diff --git a/services/audiopolicy/enginedefault/Android.mk b/services/audiopolicy/enginedefault/Android.mk
deleted file mode 100644
index ebf383b..0000000
--- a/services/audiopolicy/enginedefault/Android.mk
+++ /dev/null
@@ -1,57 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-# Component build
-#######################################################################
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
- src/Engine.cpp \
- src/EngineInstance.cpp \
- ../engine/common/src/VolumeCurve.cpp \
- ../engine/common/src/ProductStrategy.cpp \
- ../engine/common/src/EngineBase.cpp \
- ../engine/common/src/VolumeGroup.cpp
-
-audio_policy_engine_includes_common := \
- $(LOCAL_PATH)/include
-
-LOCAL_CFLAGS += \
- -Wall \
- -Werror \
- -Wextra \
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := \
- $(audio_policy_engine_includes_common)
-
-LOCAL_C_INCLUDES := \
- $(audio_policy_engine_includes_common) \
- $(TARGET_OUT_HEADERS)/hw \
- $(call include-path-for, frameworks-av) \
- $(call include-path-for, audio-utils) \
- $(call include-path-for, bionic)
-
-LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
-
-LOCAL_MODULE := libaudiopolicyenginedefault
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_HEADER_LIBRARIES := libbase_headers
-
-LOCAL_STATIC_LIBRARIES := \
- libaudiopolicycomponents
-
-LOCAL_SHARED_LIBRARIES := \
- liblog \
- libcutils \
- libutils \
- libmedia_helper \
- libaudiopolicyengineconfig \
- libaudiopolicy
-
-LOCAL_HEADER_LIBRARIES := \
- libaudiopolicycommon \
- libaudiopolicyengine_common_headers \
- libaudiopolicyengine_interface_headers
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/services/audiopolicy/enginedefault/config/example/Android.mk b/services/audiopolicy/enginedefault/config/example/Android.mk
index f06ee4c..0badac8 100644
--- a/services/audiopolicy/enginedefault/config/example/Android.mk
+++ b/services/audiopolicy/enginedefault/config/example/Android.mk
@@ -7,28 +7,26 @@
ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), phone_default)
include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_configuration_phone.xml
-LOCAL_MODULE_STEM := audio_policy_engine_configuration.xml
+LOCAL_MODULE := audio_policy_engine_configuration.xml
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := ETC
LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := phone/$(LOCAL_MODULE_STEM)
+LOCAL_SRC_FILES := phone/$(LOCAL_MODULE)
LOCAL_REQUIRED_MODULES := \
- audio_policy_engine_product_strategies_phone.xml \
+ audio_policy_engine_product_strategies.xml \
audio_policy_engine_stream_volumes.xml \
audio_policy_engine_default_stream_volumes.xml
include $(BUILD_PREBUILT)
include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_product_strategies_phone.xml
-LOCAL_MODULE_STEM := audio_policy_engine_product_strategies.xml
+LOCAL_MODULE := audio_policy_engine_product_strategies.xml
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := ETC
LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := phone/$(LOCAL_MODULE_STEM)
+LOCAL_SRC_FILES := phone/$(LOCAL_MODULE)
include $(BUILD_PREBUILT)
include $(CLEAR_VARS)
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index f191738..66a6965 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -727,7 +727,7 @@
}
sp<DeviceDescriptor> Engine::getInputDeviceForAttributes(const audio_attributes_t &attr,
- AudioMix **mix) const
+ sp<AudioPolicyMix> *mix) const
{
const auto &policyMixes = getApmObserver()->getAudioPolicyMixCollection();
const auto &availableInputDevices = getApmObserver()->getAvailableInputDevices();
diff --git a/services/audiopolicy/enginedefault/src/Engine.h b/services/audiopolicy/enginedefault/src/Engine.h
index d8a3698..d5dfacc 100644
--- a/services/audiopolicy/enginedefault/src/Engine.h
+++ b/services/audiopolicy/enginedefault/src/Engine.h
@@ -66,7 +66,7 @@
bool fromCache = false) const override;
sp<DeviceDescriptor> getInputDeviceForAttributes(
- const audio_attributes_t &attr, AudioMix **mix = nullptr) const override;
+ const audio_attributes_t &attr, sp<AudioPolicyMix> *mix = nullptr) const override;
void updateDeviceSelectionCache() override;
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index c969af3..e8e9fa6 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -217,10 +217,11 @@
&& strncmp(device_address, "0", AUDIO_DEVICE_MAX_ADDRESS_LEN) != 0) {
for (audio_io_handle_t output : outputs) {
sp<SwAudioOutputDescriptor> desc = mOutputs.valueFor(output);
- if (desc->mPolicyMix != nullptr
- && desc->mPolicyMix->mMixType == MIX_TYPE_RECORDERS
+ sp<AudioPolicyMix> policyMix = desc->mPolicyMix.promote();
+ if (policyMix != nullptr
+ && policyMix->mMixType == MIX_TYPE_RECORDERS
&& strncmp(device_address,
- desc->mPolicyMix->mDeviceAddress.string(),
+ policyMix->mDeviceAddress.string(),
AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0) {
doCheckForDeviceAndOutputChanges = false;
break;
@@ -968,7 +969,7 @@
}
if (usePrimaryOutputFromPolicyMixes) {
*output = policyDesc->mIoHandle;
- AudioMix *mix = policyDesc->mPolicyMix;
+ sp<AudioPolicyMix> mix = policyDesc->mPolicyMix.promote();
sp<DeviceDescriptor> deviceDesc =
mAvailableOutputDevices.getDevice(mix->mDeviceType,
mix->mDeviceAddress,
@@ -1022,7 +1023,8 @@
}
}
if (*output == AUDIO_IO_HANDLE_NONE) {
- *output = getOutputForDevices(outputDevices, session, *stream, config, flags);
+ *output = getOutputForDevices(outputDevices, session, *stream, config,
+ flags, attr->flags & AUDIO_FLAG_MUTE_HAPTIC);
}
if (*output == AUDIO_IO_HANDLE_NONE) {
return INVALID_OPERATION;
@@ -1083,7 +1085,7 @@
new TrackClientDescriptor(*portId, uid, session, resultAttr, clientConfig,
sanitizedRequestedPortId, *stream,
mEngine->getProductStrategyForAttributes(resultAttr),
- streamToVolumeSource(*stream),
+ toVolumeSource(resultAttr),
*flags, isRequestedDeviceForExclusiveUse,
std::move(weakSecondaryOutputDescs));
sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(*output);
@@ -1100,11 +1102,16 @@
audio_session_t session,
audio_stream_type_t stream,
const audio_config_t *config,
- audio_output_flags_t *flags)
+ audio_output_flags_t *flags,
+ bool forceMutingHaptic)
{
audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
status_t status;
+ // Discard haptic channel mask when forcing muting haptic channels.
+ audio_channel_mask_t channelMask = forceMutingHaptic
+ ? (config->channel_mask & ~AUDIO_CHANNEL_HAPTIC_ALL) : config->channel_mask;
+
// open a direct output if required by specified parameters
//force direct flag if offload flag is set: offloading implies a direct output stream
// and all common behaviors are driven by checking only the direct flag
@@ -1141,7 +1148,7 @@
// and not explicitly requested
if (((*flags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) &&
audio_is_linear_pcm(config->format) && config->sample_rate <= SAMPLE_RATE_HZ_MAX &&
- audio_channel_count_from_out_mask(config->channel_mask) <= 2) {
+ audio_channel_count_from_out_mask(channelMask) <= 2) {
goto non_direct_output;
}
@@ -1157,7 +1164,7 @@
profile = getProfileForOutput(devices,
config->sample_rate,
config->format,
- config->channel_mask,
+ channelMask,
(audio_output_flags_t)*flags,
true /* directOnly */);
}
@@ -1171,7 +1178,7 @@
// and configured with same parameters
if ((config->sample_rate == desc->mSamplingRate) &&
(config->format == desc->mFormat) &&
- (config->channel_mask == desc->mChannelMask) &&
+ (channelMask == desc->mChannelMask) &&
(session == desc->mDirectClientSession)) {
desc->mDirectOpenCount++;
ALOGI("%s reusing direct output %d for session %d", __func__,
@@ -1213,11 +1220,11 @@
if (status != NO_ERROR ||
(config->sample_rate != 0 && config->sample_rate != outputDesc->mSamplingRate) ||
(config->format != AUDIO_FORMAT_DEFAULT && config->format != outputDesc->mFormat) ||
- (config->channel_mask != 0 && config->channel_mask != outputDesc->mChannelMask)) {
+ (channelMask != 0 && channelMask != outputDesc->mChannelMask)) {
ALOGV("%s failed opening direct output: output %d sample rate %d %d,"
"format %d %d, channel mask %04x %04x", __func__, output, config->sample_rate,
outputDesc->mSamplingRate, config->format, outputDesc->mFormat,
- config->channel_mask, outputDesc->mChannelMask);
+ channelMask, outputDesc->mChannelMask);
if (output != AUDIO_IO_HANDLE_NONE) {
outputDesc->close();
}
@@ -1258,12 +1265,11 @@
// at this stage we should ignore the DIRECT flag as no direct output could be found earlier
*flags = (audio_output_flags_t)(*flags & ~AUDIO_OUTPUT_FLAG_DIRECT);
- output = selectOutput(outputs, *flags, config->format,
- config->channel_mask, config->sample_rate);
+ output = selectOutput(outputs, *flags, config->format, channelMask, config->sample_rate);
}
ALOGW_IF((output == 0), "getOutputForDevices() could not find output for stream %d, "
"sampling rate %d, format %#x, channels %#x, flags %#x",
- stream, config->sample_rate, config->format, config->channel_mask, *flags);
+ stream, config->sample_rate, config->format, channelMask, *flags);
return output;
}
@@ -1597,10 +1603,9 @@
(outputDesc->getPatchHandle() == AUDIO_PATCH_HANDLE_NONE);
DeviceVector devices;
- AudioMix *policyMix = NULL;
+ sp<AudioPolicyMix> policyMix = outputDesc->mPolicyMix.promote();
const char *address = NULL;
- if (outputDesc->mPolicyMix != NULL) {
- policyMix = outputDesc->mPolicyMix;
+ if (policyMix != NULL) {
audio_devices_t newDeviceType;
address = policyMix->mDeviceAddress.string();
if ((policyMix->mRouteFlags & MIX_ROUTE_FLAG_LOOP_BACK) == MIX_ROUTE_FLAG_LOOP_BACK) {
@@ -1689,8 +1694,9 @@
setOutputDevices(outputDesc, devices, force, 0, NULL, requiresMuteCheck);
// apply volume rules for current stream and device if necessary
- checkAndSetVolume(stream,
- getVolumeCurves(stream).getVolumeIndex(outputDesc->devices().types()),
+ auto &curves = getVolumeCurves(client->attributes());
+ checkAndSetVolume(curves, client->volumeSource(),
+ curves.getVolumeIndex(outputDesc->devices().types()),
outputDesc,
outputDesc->devices().types());
@@ -1770,12 +1776,13 @@
if (outputDesc->getActivityCount(clientVolSrc) == 1) {
// Automatically disable the remote submix input when output is stopped on a
// re routing mix of type MIX_TYPE_RECORDERS
+ sp<AudioPolicyMix> policyMix = outputDesc->mPolicyMix.promote();
if (audio_is_remote_submix_device(outputDesc->devices().types()) &&
- outputDesc->mPolicyMix != NULL &&
- outputDesc->mPolicyMix->mMixType == MIX_TYPE_RECORDERS) {
+ policyMix != NULL &&
+ policyMix->mMixType == MIX_TYPE_RECORDERS) {
setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
- outputDesc->mPolicyMix->mDeviceAddress,
+ policyMix->mDeviceAddress,
"remote-submix", AUDIO_FORMAT_DEFAULT);
}
}
@@ -1890,7 +1897,7 @@
status_t status = NO_ERROR;
audio_source_t halInputSource;
audio_attributes_t attributes = *attr;
- AudioMix *policyMix = NULL;
+ sp<AudioPolicyMix> policyMix;
sp<DeviceDescriptor> device;
sp<AudioInputDescriptor> inputDesc;
sp<RecordClientDescriptor> clientDesc;
@@ -1987,7 +1994,7 @@
status = BAD_VALUE;
goto error;
}
- if (policyMix != nullptr) {
+ if (policyMix) {
ALOG_ASSERT(policyMix->mMixType == MIX_TYPE_RECORDERS, "Invalid Mix Type");
// there is an external policy, but this input is attached to a mix of recorders,
// meaning it receives audio injected into the framework, so the recorder doesn't
@@ -2039,7 +2046,7 @@
const audio_attributes_t &attributes,
const audio_config_base_t *config,
audio_input_flags_t flags,
- AudioMix *policyMix)
+ const sp<AudioPolicyMix> &policyMix)
{
audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
audio_source_t halInputSource = attributes.source;
@@ -2199,10 +2206,11 @@
setInputDevice(input, device, true /* force */);
if (inputDesc->activeCount() == 1) {
+ sp<AudioPolicyMix> policyMix = inputDesc->mPolicyMix.promote();
// if input maps to a dynamic policy with an activity listener, notify of state change
- if ((inputDesc->mPolicyMix != NULL)
- && ((inputDesc->mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
- mpClientInterface->onDynamicPolicyMixStateUpdate(inputDesc->mPolicyMix->mDeviceAddress,
+ if ((policyMix != NULL)
+ && ((policyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
+ mpClientInterface->onDynamicPolicyMixStateUpdate(policyMix->mDeviceAddress,
MIX_STATE_MIXING);
}
@@ -2217,10 +2225,10 @@
// For remote submix (a virtual device), we open only one input per capture request.
if (audio_is_remote_submix_device(inputDesc->getDeviceType())) {
String8 address = String8("");
- if (inputDesc->mPolicyMix == NULL) {
+ if (policyMix == NULL) {
address = String8("0");
- } else if (inputDesc->mPolicyMix->mMixType == MIX_TYPE_PLAYERS) {
- address = inputDesc->mPolicyMix->mDeviceAddress;
+ } else if (policyMix->mMixType == MIX_TYPE_PLAYERS) {
+ address = policyMix->mDeviceAddress;
}
if (address != "") {
setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
@@ -2257,10 +2265,11 @@
if (inputDesc->isActive()) {
setInputDevice(input, getNewInputDevice(inputDesc), false /* force */);
} else {
+ sp<AudioPolicyMix> policyMix = inputDesc->mPolicyMix.promote();
// if input maps to a dynamic policy with an activity listener, notify of state change
- if ((inputDesc->mPolicyMix != NULL)
- && ((inputDesc->mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
- mpClientInterface->onDynamicPolicyMixStateUpdate(inputDesc->mPolicyMix->mDeviceAddress,
+ if ((policyMix != NULL)
+ && ((policyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
+ mpClientInterface->onDynamicPolicyMixStateUpdate(policyMix->mDeviceAddress,
MIX_STATE_IDLE);
}
@@ -2268,10 +2277,10 @@
// used by a policy mix of type MIX_TYPE_RECORDERS
if (audio_is_remote_submix_device(inputDesc->getDeviceType())) {
String8 address = String8("");
- if (inputDesc->mPolicyMix == NULL) {
+ if (policyMix == NULL) {
address = String8("0");
- } else if (inputDesc->mPolicyMix->mMixType == MIX_TYPE_PLAYERS) {
- address = inputDesc->mPolicyMix->mDeviceAddress;
+ } else if (policyMix->mMixType == MIX_TYPE_PLAYERS) {
+ address = policyMix->mDeviceAddress;
}
if (address != "") {
setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
@@ -2379,131 +2388,60 @@
int index,
audio_devices_t device)
{
- auto &curves = getVolumeCurves(stream);
- // VOICE_CALL and BLUETOOTH_SCO stream have minVolumeIndex > 0 but
- // can be muted directly by an app that has MODIFY_PHONE_STATE permission.
- if (((index < curves.getVolumeIndexMin()) &&
- !((stream == AUDIO_STREAM_VOICE_CALL || stream == AUDIO_STREAM_BLUETOOTH_SCO) &&
- index == 0)) ||
- (index > curves.getVolumeIndexMax())) {
- return BAD_VALUE;
- }
- if (!audio_is_output_device(device)) {
- return BAD_VALUE;
- }
-
- // Force max volume if stream cannot be muted
- if (!curves.canBeMuted()) index = curves.getVolumeIndexMax();
-
- ALOGV("setStreamVolumeIndex() stream %d, device %08x, index %d",
- stream, device, index);
-
- // update other private stream volumes which follow this one
- for (int curStream = 0; curStream < AUDIO_STREAM_FOR_POLICY_CNT; curStream++) {
- if (!streamsMatchForvolume(stream, (audio_stream_type_t)curStream)) {
- continue;
- }
- auto &curCurves = getVolumeCurves(static_cast<audio_stream_type_t>(curStream));
- curCurves.addCurrentVolumeIndex(device, index);
- }
-
- // update volume on all outputs and streams matching the following:
- // - The requested stream (or a stream matching for volume control) is active on the output
- // - The device (or devices) selected by the engine for this stream includes
- // the requested device
- // - For non default requested device, currently selected device on the output is either the
- // requested device or one of the devices selected by the engine for this stream
- // - For default requested device (AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME), apply volume only if
- // no specific device volume value exists for currently selected device.
- status_t status = NO_ERROR;
- for (size_t i = 0; i < mOutputs.size(); i++) {
- sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
- audio_devices_t curDevice = desc->devices().types();
- for (int curStream = 0; curStream < AUDIO_STREAM_FOR_POLICY_CNT; curStream++) {
- if (!(streamsMatchForvolume(stream, (audio_stream_type_t)curStream))) {
- continue;
- }
- if (!(desc->isActive(streamToVolumeSource((audio_stream_type_t)curStream)) || isInCall())) {
- continue;
- }
- audio_devices_t curStreamDevice = Volume::getDeviceForVolume(
- mEngine->getOutputDevicesForStream((audio_stream_type_t)curStream,
- false /*fromCache*/).types());
- if ((device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) &&
- ((curStreamDevice & device) == 0)) {
- continue;
- }
- bool applyVolume;
- if (device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) {
- curStreamDevice |= device;
- applyVolume = (Volume::getDeviceForVolume(curDevice) & curStreamDevice) != 0;
- } else {
- applyVolume = !curves.hasVolumeIndexForDevice(curStreamDevice);
- }
- // rescale index before applying to curStream as ranges may be different for
- // stream and curStream
- int idx = rescaleVolumeIndex(index, stream, (audio_stream_type_t)curStream);
- if (applyVolume) {
- //FIXME: workaround for truncated touch sounds
- // delayed volume change for system stream to be removed when the problem is
- // handled by system UI
- status_t volStatus = checkAndSetVolume(
- (audio_stream_type_t)curStream, idx, desc, curDevice,
- (stream == AUDIO_STREAM_SYSTEM) ?
- TOUCH_SOUND_FIXED_DELAY_MS : 0);
- if (volStatus != NO_ERROR) {
- status = volStatus;
- }
- }
- }
- }
- return status;
+ auto attributes = mEngine->getAttributesForStreamType(stream);
+ ALOGV("%s: stream %s attributes=%s", __func__,
+ toString(stream).c_str(), toString(attributes).c_str());
+ return setVolumeIndexForAttributes(attributes, index, device);
}
status_t AudioPolicyManager::getStreamVolumeIndex(audio_stream_type_t stream,
- int *index,
- audio_devices_t device)
+ int *index,
+ audio_devices_t device)
{
- if (index == NULL) {
- return BAD_VALUE;
- }
- if (!audio_is_output_device(device)) {
- return BAD_VALUE;
- }
// if device is AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME, return volume for device selected for this
// stream by the engine.
if (device == AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) {
device = mEngine->getOutputDevicesForStream(stream, true /*fromCache*/).types();
}
- device = Volume::getDeviceForVolume(device);
-
- *index = getVolumeCurves(stream).getVolumeIndex(device);
- ALOGV("getStreamVolumeIndex() stream %d device %08x index %d", stream, device, *index);
- return NO_ERROR;
+ return getVolumeIndex(getVolumeCurves(stream), *index, device);
}
-status_t AudioPolicyManager::setVolumeIndexForAttributes(const audio_attributes_t &attr,
+status_t AudioPolicyManager::setVolumeIndexForAttributes(const audio_attributes_t &attributes,
int index,
audio_devices_t device)
{
// Get Volume group matching the Audio Attributes
- auto volumeGroup = mEngine->getVolumeGroupForAttributes(attr);
- if (volumeGroup == VOLUME_GROUP_NONE) {
- ALOGD("%s: could not find group matching with %s", __FUNCTION__, toString(attr).c_str());
+ auto group = mEngine->getVolumeGroupForAttributes(attributes);
+ if (group == VOLUME_GROUP_NONE) {
+ ALOGD("%s: no group matching with %s", __FUNCTION__, toString(attributes).c_str());
return BAD_VALUE;
}
- ALOGD("%s: FOUND group %d matching with %s", __FUNCTION__, volumeGroup, toString(attr).c_str());
- return setVolumeGroupIndex(getVolumeCurves(attr), volumeGroup, index, device, attr);
-}
-
-status_t AudioPolicyManager::setVolumeGroupIndex(IVolumeCurves &curves, volume_group_t group,
- int index,
- audio_devices_t device,
- const audio_attributes_t /*attributes*/)
-{
- ALOGVV("%s: group=%d", __func__, group);
+ ALOGV("%s: group %d matching with %s", __FUNCTION__, group, toString(attributes).c_str());
status_t status = NO_ERROR;
- setVolumeCurveIndex(group, index, device, curves);
+ IVolumeCurves &curves = getVolumeCurves(attributes);
+ VolumeSource vs = toVolumeSource(group);
+ product_strategy_t strategy = mEngine->getProductStrategyForAttributes(attributes);
+
+ status = setVolumeCurveIndex(index, device, curves);
+ if (status != NO_ERROR) {
+ ALOGE("%s failed to set curve index for group %d device 0x%X", __func__, group, device);
+ return status;
+ }
+
+ audio_devices_t curSrcDevice;
+ auto curCurvAttrs = curves.getAttributes();
+ if (!curCurvAttrs.empty() && curCurvAttrs.front() != defaultAttr) {
+ auto attr = curCurvAttrs.front();
+ curSrcDevice = mEngine->getOutputDevicesForAttributes(attr, nullptr, false).types();
+ } else if (!curves.getStreamTypes().empty()) {
+ auto stream = curves.getStreamTypes().front();
+ curSrcDevice = mEngine->getOutputDevicesForStream(stream, false).types();
+ } else {
+ ALOGE("%s: Invalid src %d: no valid attributes nor stream",__func__, vs);
+ return BAD_VALUE;
+ }
+ curSrcDevice = Volume::getDeviceForVolume(curSrcDevice);
+
// update volume on all outputs and streams matching the following:
// - The requested stream (or a stream matching for volume control) is active on the output
// - The device (or devices) selected by the engine for this stream includes
@@ -2512,21 +2450,96 @@
// requested device or one of the devices selected by the engine for this stream
// - For default requested device (AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME), apply volume only if
// no specific device volume value exists for currently selected device.
- // @TODO
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
+ audio_devices_t curDevice = desc->devices().types();
+
+ // Inter / intra volume group priority management: Loop on strategies arranged by priority
+ // If a higher priority strategy is active, and the output is routed to a device with a
+ // HW Gain management, do not change the volume
+ bool applyVolume = false;
+ if (desc->useHwGain()) {
+ if (!(desc->isActive(group) || isInCall())) {
+ continue;
+ }
+ for (const auto &productStrategy : mEngine->getOrderedProductStrategies()) {
+ auto activeClients = desc->clientsList(true /*activeOnly*/, productStrategy,
+ false /*preferredDevice*/);
+ if (activeClients.empty()) {
+ continue;
+ }
+ bool isPreempted = false;
+ bool isHigherPriority = productStrategy < strategy;
+ for (const auto &client : activeClients) {
+ if (isHigherPriority && (client->volumeSource() != vs)) {
+ ALOGV("%s: Strategy=%d (\nrequester:\n"
+ " group %d, volumeGroup=%d attributes=%s)\n"
+ " higher priority source active:\n"
+ " volumeGroup=%d attributes=%s) \n"
+ " on output %zu, bailing out", __func__, productStrategy,
+ group, group, toString(attributes).c_str(),
+ client->volumeSource(), toString(client->attributes()).c_str(), i);
+ applyVolume = false;
+ isPreempted = true;
+ break;
+ }
+ // However, continue for loop to ensure no higher prio clients running on output
+ if (client->volumeSource() == vs) {
+ applyVolume = true;
+ }
+ }
+ if (isPreempted || applyVolume) {
+ break;
+ }
+ }
+ if (!applyVolume) {
+ continue; // next output
+ }
+ status_t volStatus = checkAndSetVolume(curves, vs, index, desc, curDevice,
+ (vs == toVolumeSource(AUDIO_STREAM_SYSTEM)?
+ TOUCH_SOUND_FIXED_DELAY_MS : 0));
+ if (volStatus != NO_ERROR) {
+ status = volStatus;
+ }
+ continue;
+ }
+ if (!(desc->isActive(vs) || isInCall())) {
+ continue;
+ }
+ if ((device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) && ((curDevice & device) == 0)) {
+ continue;
+ }
+ if (device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) {
+ curSrcDevice |= device;
+ applyVolume = (Volume::getDeviceForVolume(curDevice) & curSrcDevice) != 0;
+ } else {
+ applyVolume = !curves.hasVolumeIndexForDevice(curSrcDevice);
+ }
+ if (applyVolume) {
+ //FIXME: workaround for truncated touch sounds
+ // delayed volume change for system stream to be removed when the problem is
+ // handled by system UI
+ status_t volStatus = checkAndSetVolume(
+ curves, vs, index, desc, curDevice,
+ ((vs == toVolumeSource(AUDIO_STREAM_SYSTEM))?
+ TOUCH_SOUND_FIXED_DELAY_MS : 0));
+ if (volStatus != NO_ERROR) {
+ status = volStatus;
+ }
+ }
+ }
mpClientInterface->onAudioVolumeGroupChanged(group, 0 /*flags*/);
return status;
}
-status_t AudioPolicyManager::setVolumeCurveIndex(volume_group_t volumeGroup,
- int index,
+status_t AudioPolicyManager::setVolumeCurveIndex(int index,
audio_devices_t device,
IVolumeCurves &volumeCurves)
{
// VOICE_CALL stream has minVolumeIndex > 0 but can be muted directly by an
// app that has MODIFY_PHONE_STATE permission.
- // If voice is member of the volume group, it will contaminate all the member of this group
- auto streams = mEngine->getStreamTypesForVolumeGroup(volumeGroup);
- if (((index < volumeCurves.getVolumeIndexMin()) && !(hasVoiceStream(streams) && index == 0)) ||
+ bool hasVoice = hasVoiceStream(volumeCurves.getStreamTypes());
+ if (((index < volumeCurves.getVolumeIndexMin()) && !(hasVoice && index == 0)) ||
(index > volumeCurves.getVolumeIndexMax())) {
ALOGD("%s: wrong index %d min=%d max=%d", __FUNCTION__, index,
volumeCurves.getVolumeIndexMin(), volumeCurves.getVolumeIndexMax());
@@ -2539,7 +2552,7 @@
// Force max volume if stream cannot be muted
if (!volumeCurves.canBeMuted()) index = volumeCurves.getVolumeIndexMax();
- ALOGD("%s device %08x, index %d", __FUNCTION__ , device, index);
+ ALOGV("%s device %08x, index %d", __FUNCTION__ , device, index);
volumeCurves.addCurrentVolumeIndex(device, index);
return NO_ERROR;
}
@@ -2701,19 +2714,12 @@
bool AudioPolicyManager::isStreamActive(audio_stream_type_t stream, uint32_t inPastMs) const
{
- bool active = false;
- for (int curStream = 0; curStream < AUDIO_STREAM_FOR_POLICY_CNT && !active; curStream++) {
- if (!streamsMatchForvolume(stream, (audio_stream_type_t)curStream)) {
- continue;
- }
- active = mOutputs.isActive(streamToVolumeSource((audio_stream_type_t)curStream), inPastMs);
- }
- return active;
+ return mOutputs.isActive(toVolumeSource(stream), inPastMs);
}
bool AudioPolicyManager::isStreamActiveRemotely(audio_stream_type_t stream, uint32_t inPastMs) const
{
- return mOutputs.isActiveRemotely(streamToVolumeSource((audio_stream_type_t)stream), inPastMs);
+ return mOutputs.isActiveRemotely(toVolumeSource(stream), inPastMs);
}
bool AudioPolicyManager::isSourceActive(audio_source_t source) const
@@ -3742,11 +3748,11 @@
struct audio_patch dummyPatch = {};
sp<AudioPatch> patchDesc = new AudioPatch(&dummyPatch, uid);
- sp<SourceClientDescriptor> sourceDesc = new SourceClientDescriptor(
- *portId, uid, *attributes, patchDesc, srcDevice,
- mEngine->getStreamTypeForAttributes(*attributes),
- mEngine->getProductStrategyForAttributes(*attributes),
- streamToVolumeSource(mEngine->getStreamTypeForAttributes(*attributes)));
+ sp<SourceClientDescriptor> sourceDesc =
+ new SourceClientDescriptor(*portId, uid, *attributes, patchDesc, srcDevice,
+ mEngine->getStreamTypeForAttributes(*attributes),
+ mEngine->getProductStrategyForAttributes(*attributes),
+ toVolumeSource(*attributes));
status_t status = connectAudioSource(sourceDesc);
if (status == NO_ERROR) {
@@ -3911,7 +3917,7 @@
float AudioPolicyManager::getStreamVolumeDB(
audio_stream_type_t stream, int index, audio_devices_t device)
{
- return computeVolume(stream, index, device);
+ return computeVolume(getVolumeCurves(stream), toVolumeSource(stream), index, device);
}
status_t AudioPolicyManager::getSurroundFormats(unsigned int *numSurroundFormats,
@@ -4577,7 +4583,7 @@
sp<AudioPolicyMix> policyMix;
if (mPolicyMixes.getAudioPolicyMix(address, policyMix) == NO_ERROR) {
policyMix->setOutput(desc);
- desc->mPolicyMix = policyMix->getMix();
+ desc->mPolicyMix = policyMix;
} else {
ALOGW("checkOutputsForDevice() cannot find policy for address %s",
address.string());
@@ -5287,11 +5293,10 @@
// mute/unmute AUDIO_STREAM_TTS on all outputs
ALOGV("\t muting %d", mute);
uint32_t maxLatency = 0;
+ auto ttsVolumeSource = toVolumeSource(AUDIO_STREAM_TTS);
for (size_t i = 0; i < mOutputs.size(); i++) {
sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
- setStreamMute(AUDIO_STREAM_TTS, mute/*on*/,
- desc,
- 0 /*delay*/, AUDIO_DEVICE_NONE);
+ setVolumeSourceMute(ttsVolumeSource, mute/*on*/, desc, 0 /*delay*/, AUDIO_DEVICE_NONE);
const uint32_t latency = desc->latency() * 2;
if (latency > maxLatency) {
maxLatency = latency;
@@ -5375,15 +5380,12 @@
if (muteWaitMs < tempMuteWaitMs) {
muteWaitMs = tempMuteWaitMs;
}
-
- for (const auto &productStrategy : productStrategies) {
- if (outputDesc->isStrategyActive(productStrategy)) {
- // make sure that we do not start the temporary mute period too early in case of
- // delayed device change
- setStrategyMute(productStrategy, true, outputDesc, delayMs);
- setStrategyMute(productStrategy, false, outputDesc, delayMs + tempMuteDurationMs,
+ for (const auto &activeVs : outputDesc->getActiveVolumeSources()) {
+ // make sure that we do not start the temporary mute period too early in case of
+ // delayed device change
+ setVolumeSourceMute(activeVs, true, outputDesc, delayMs);
+ setVolumeSourceMute(activeVs, false, outputDesc, delayMs + tempMuteDurationMs,
devices.types());
- }
}
}
@@ -5607,51 +5609,51 @@
return NULL;
}
-float AudioPolicyManager::computeVolume(audio_stream_type_t stream,
+float AudioPolicyManager::computeVolume(IVolumeCurves &curves,
+ VolumeSource volumeSource,
int index,
audio_devices_t device)
{
- auto &curves = getVolumeCurves(stream);
float volumeDb = curves.volIndexToDb(Volume::getDeviceCategory(device), index);
// handle the case of accessibility active while a ringtone is playing: if the ringtone is much
// louder than the accessibility prompt, the prompt cannot be heard, thus masking the touch
// exploration of the dialer UI. In this situation, bring the accessibility volume closer to
// the ringtone volume
- if ((stream == AUDIO_STREAM_ACCESSIBILITY)
- && (AUDIO_MODE_RINGTONE == mEngine->getPhoneState())
- && isStreamActive(AUDIO_STREAM_RING, 0)) {
- const float ringVolumeDB = computeVolume(AUDIO_STREAM_RING, index, device);
- return ringVolumeDB - 4 > volumeDb ? ringVolumeDB - 4 : volumeDb;
+ const auto callVolumeSrc = toVolumeSource(AUDIO_STREAM_VOICE_CALL);
+ const auto ringVolumeSrc = toVolumeSource(AUDIO_STREAM_RING);
+ const auto musicVolumeSrc = toVolumeSource(AUDIO_STREAM_MUSIC);
+ const auto alarmVolumeSrc = toVolumeSource(AUDIO_STREAM_ALARM);
+
+ if (volumeSource == toVolumeSource(AUDIO_STREAM_ACCESSIBILITY)
+ && (AUDIO_MODE_RINGTONE == mEngine->getPhoneState()) &&
+ mOutputs.isActive(ringVolumeSrc, 0)) {
+ auto &ringCurves = getVolumeCurves(AUDIO_STREAM_RING);
+ const float ringVolumeDb = computeVolume(ringCurves, ringVolumeSrc, index, device);
+ return ringVolumeDb - 4 > volumeDb ? ringVolumeDb - 4 : volumeDb;
}
// in-call: always cap volume by voice volume + some low headroom
- if ((stream != AUDIO_STREAM_VOICE_CALL) &&
- (isInCall() || mOutputs.isActiveLocally(streamToVolumeSource(AUDIO_STREAM_VOICE_CALL)))) {
- switch (stream) {
- case AUDIO_STREAM_SYSTEM:
- case AUDIO_STREAM_RING:
- case AUDIO_STREAM_MUSIC:
- case AUDIO_STREAM_ALARM:
- case AUDIO_STREAM_NOTIFICATION:
- case AUDIO_STREAM_ENFORCED_AUDIBLE:
- case AUDIO_STREAM_DTMF:
- case AUDIO_STREAM_ACCESSIBILITY: {
- int voiceVolumeIndex = getVolumeCurves(AUDIO_STREAM_VOICE_CALL).getVolumeIndex(device);
- const float maxVoiceVolDb =
- computeVolume(AUDIO_STREAM_VOICE_CALL, voiceVolumeIndex, device)
+ if ((volumeSource != callVolumeSrc && (isInCall() ||
+ mOutputs.isActiveLocally(callVolumeSrc))) &&
+ (volumeSource == toVolumeSource(AUDIO_STREAM_SYSTEM) ||
+ volumeSource == ringVolumeSrc || volumeSource == musicVolumeSrc ||
+ volumeSource == alarmVolumeSrc ||
+ volumeSource == toVolumeSource(AUDIO_STREAM_NOTIFICATION) ||
+ volumeSource == toVolumeSource(AUDIO_STREAM_ENFORCED_AUDIBLE) ||
+ volumeSource == toVolumeSource(AUDIO_STREAM_DTMF) ||
+ volumeSource == toVolumeSource(AUDIO_STREAM_ACCESSIBILITY))) {
+ auto &voiceCurves = getVolumeCurves(callVolumeSrc);
+ int voiceVolumeIndex = voiceCurves.getVolumeIndex(device);
+ const float maxVoiceVolDb =
+ computeVolume(voiceCurves, callVolumeSrc, voiceVolumeIndex, device)
+ IN_CALL_EARPIECE_HEADROOM_DB;
- if (volumeDb > maxVoiceVolDb) {
- ALOGV("computeVolume() stream %d at vol=%f overriden by stream %d at vol=%f",
- stream, volumeDb, AUDIO_STREAM_VOICE_CALL, maxVoiceVolDb);
- volumeDb = maxVoiceVolDb;
- }
- } break;
- default:
- break;
+ if (volumeDb > maxVoiceVolDb) {
+ ALOGV("%s volume source %d at vol=%f overriden by volume group %d at vol=%f", __func__,
+ volumeSource, volumeDb, callVolumeSrc, maxVoiceVolDb);
+ volumeDb = maxVoiceVolDb;
}
}
-
// if a headset is connected, apply the following rules to ring tones and notifications
// to avoid sound level bursts in user's ears:
// - always attenuate notifications volume by 6dB
@@ -5659,19 +5661,17 @@
// speaker is part of the select devices
// - if music is playing, always limit the volume to current music volume,
// with a minimum threshold at -36dB so that notification is always perceived.
- if ((device & (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
- AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
- AUDIO_DEVICE_OUT_WIRED_HEADSET |
- AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
- AUDIO_DEVICE_OUT_USB_HEADSET |
- AUDIO_DEVICE_OUT_HEARING_AID)) &&
- ((stream == AUDIO_STREAM_ALARM || stream == AUDIO_STREAM_RING)
- || (stream == AUDIO_STREAM_NOTIFICATION)
- || (stream == AUDIO_STREAM_SYSTEM)
- || ((stream == AUDIO_STREAM_ENFORCED_AUDIBLE) &&
- (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) ==
- AUDIO_POLICY_FORCE_NONE))) &&
- getVolumeCurves(stream).canBeMuted()) {
+ if ((device & (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP | AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
+ AUDIO_DEVICE_OUT_WIRED_HEADSET | AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
+ AUDIO_DEVICE_OUT_USB_HEADSET | AUDIO_DEVICE_OUT_HEARING_AID)) &&
+ ((volumeSource == alarmVolumeSrc ||
+ volumeSource == ringVolumeSrc) ||
+ (volumeSource == toVolumeSource(AUDIO_STREAM_NOTIFICATION)) ||
+ (volumeSource == toVolumeSource(AUDIO_STREAM_SYSTEM)) ||
+ ((volumeSource == toVolumeSource(AUDIO_STREAM_ENFORCED_AUDIBLE)) &&
+ (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_NONE))) &&
+ curves.canBeMuted()) {
+
// when the phone is ringing we must consider that music could have been paused just before
// by the music application and behave as if music was active if the last music track was
// just stopped
@@ -5681,29 +5681,29 @@
audio_devices_t musicDevice =
mEngine->getOutputDevicesForAttributes(attributes_initializer(AUDIO_USAGE_MEDIA),
nullptr, true /*fromCache*/).types();
- float musicVolDB = computeVolume(AUDIO_STREAM_MUSIC,
- getVolumeCurves(AUDIO_STREAM_MUSIC).getVolumeIndex(musicDevice),
- musicDevice);
- float minVolDB = (musicVolDB > SONIFICATION_HEADSET_VOLUME_MIN_DB) ?
- musicVolDB : SONIFICATION_HEADSET_VOLUME_MIN_DB;
- if (volumeDb > minVolDB) {
- volumeDb = minVolDB;
- ALOGV("computeVolume limiting volume to %f musicVol %f", minVolDB, musicVolDB);
+ auto &musicCurves = getVolumeCurves(AUDIO_STREAM_MUSIC);
+ float musicVolDb = computeVolume(musicCurves, musicVolumeSrc,
+ musicCurves.getVolumeIndex(musicDevice), musicDevice);
+ float minVolDb = (musicVolDb > SONIFICATION_HEADSET_VOLUME_MIN_DB) ?
+ musicVolDb : SONIFICATION_HEADSET_VOLUME_MIN_DB;
+ if (volumeDb > minVolDb) {
+ volumeDb = minVolDb;
+ ALOGV("computeVolume limiting volume to %f musicVol %f", minVolDb, musicVolDb);
}
if (device & (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
- AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES)) {
+ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES)) {
// on A2DP, also ensure notification volume is not too low compared to media when
// intended to be played
if ((volumeDb > -96.0f) &&
- (musicVolDB - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB > volumeDb)) {
- ALOGV("computeVolume increasing volume for stream=%d device=0x%X from %f to %f",
- stream, device,
- volumeDb, musicVolDB - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB);
- volumeDb = musicVolDB - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB;
+ (musicVolDb - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB > volumeDb)) {
+ ALOGV("%s increasing volume for volume source=%d device=0x%X from %f to %f",
+ __func__, volumeSource, device, volumeDb,
+ musicVolDb - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB);
+ volumeDb = musicVolDb - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB;
}
}
} else if ((Volume::getDeviceForVolume(device) != AUDIO_DEVICE_OUT_SPEAKER) ||
- (stream != AUDIO_STREAM_ALARM && stream != AUDIO_STREAM_RING)) {
+ (!(volumeSource == alarmVolumeSrc || volumeSource == ringVolumeSrc))) {
volumeDb += SONIFICATION_HEADSET_VOLUME_FACTOR_DB;
}
}
@@ -5712,14 +5712,14 @@
}
int AudioPolicyManager::rescaleVolumeIndex(int srcIndex,
- audio_stream_type_t srcStream,
- audio_stream_type_t dstStream)
+ VolumeSource fromVolumeSource,
+ VolumeSource toVolumeSource)
{
- if (srcStream == dstStream) {
+ if (fromVolumeSource == toVolumeSource) {
return srcIndex;
}
- auto &srcCurves = getVolumeCurves(srcStream);
- auto &dstCurves = getVolumeCurves(dstStream);
+ auto &srcCurves = getVolumeCurves(fromVolumeSource);
+ auto &dstCurves = getVolumeCurves(toVolumeSource);
float minSrc = (float)srcCurves.getVolumeIndexMin();
float maxSrc = (float)srcCurves.getVolumeIndexMax();
float minDst = (float)dstCurves.getVolumeIndexMin();
@@ -5737,58 +5737,61 @@
return (int)(minDst + ((srcIndex - minSrc) * (maxDst - minDst)) / (maxSrc - minSrc));
}
-status_t AudioPolicyManager::checkAndSetVolume(audio_stream_type_t stream,
+status_t AudioPolicyManager::checkAndSetVolume(IVolumeCurves &curves,
+ VolumeSource volumeSource,
int index,
const sp<AudioOutputDescriptor>& outputDesc,
audio_devices_t device,
int delayMs,
bool force)
{
- // do not change actual stream volume if the stream is muted
- if (outputDesc->isMuted(streamToVolumeSource(stream))) {
- ALOGVV("%s() stream %d muted count %d", __func__, stream, outputDesc->getMuteCount(stream));
+ // do not change actual attributes volume if the attributes is muted
+ if (outputDesc->isMuted(volumeSource)) {
+ ALOGVV("%s: volume source %d muted count %d active=%d", __func__, volumeSource,
+ outputDesc->getMuteCount(volumeSource), outputDesc->isActive(volumeSource));
return NO_ERROR;
}
+ VolumeSource callVolSrc = toVolumeSource(AUDIO_STREAM_VOICE_CALL);
+ VolumeSource btScoVolSrc = toVolumeSource(AUDIO_STREAM_BLUETOOTH_SCO);
+ bool isVoiceVolSrc = callVolSrc == volumeSource;
+ bool isBtScoVolSrc = btScoVolSrc == volumeSource;
+
audio_policy_forced_cfg_t forceUseForComm =
mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION);
// do not change in call volume if bluetooth is connected and vice versa
- if ((stream == AUDIO_STREAM_VOICE_CALL && forceUseForComm == AUDIO_POLICY_FORCE_BT_SCO) ||
- (stream == AUDIO_STREAM_BLUETOOTH_SCO && forceUseForComm != AUDIO_POLICY_FORCE_BT_SCO)) {
- ALOGV("checkAndSetVolume() cannot set stream %d volume with force use = %d for comm",
- stream, forceUseForComm);
+ // if sco and call follow same curves, bypass forceUseForComm
+ if ((callVolSrc != btScoVolSrc) &&
+ ((isVoiceVolSrc && forceUseForComm == AUDIO_POLICY_FORCE_BT_SCO) ||
+ (isBtScoVolSrc && forceUseForComm != AUDIO_POLICY_FORCE_BT_SCO))) {
+ ALOGV("%s cannot set volume group %d volume with force use = %d for comm", __func__,
+ volumeSource, forceUseForComm);
return INVALID_OPERATION;
}
-
if (device == AUDIO_DEVICE_NONE) {
device = outputDesc->devices().types();
}
- float volumeDb = computeVolume(stream, index, device);
+ float volumeDb = computeVolume(curves, volumeSource, index, device);
if (outputDesc->isFixedVolume(device) ||
// Force VoIP volume to max for bluetooth SCO
- ((stream == AUDIO_STREAM_VOICE_CALL || stream == AUDIO_STREAM_BLUETOOTH_SCO) &&
- (device & AUDIO_DEVICE_OUT_ALL_SCO) != 0)) {
+ ((isVoiceVolSrc || isBtScoVolSrc) && (device & AUDIO_DEVICE_OUT_ALL_SCO) != 0)) {
volumeDb = 0.0f;
}
+ outputDesc->setVolume(volumeDb, volumeSource, curves.getStreamTypes(), device, delayMs, force);
- outputDesc->setVolume(volumeDb, stream, device, delayMs, force);
-
- if (stream == AUDIO_STREAM_VOICE_CALL ||
- stream == AUDIO_STREAM_BLUETOOTH_SCO) {
+ if (isVoiceVolSrc || isBtScoVolSrc) {
float voiceVolume;
// Force voice volume to max for bluetooth SCO as volume is managed by the headset
- if (stream == AUDIO_STREAM_VOICE_CALL) {
- voiceVolume = (float)index/(float)getVolumeCurves(stream).getVolumeIndexMax();
+ if (isVoiceVolSrc) {
+ voiceVolume = (float)index/(float)curves.getVolumeIndexMax();
} else {
voiceVolume = 1.0;
}
-
if (voiceVolume != mLastVoiceVolume) {
mpClientInterface->setVoiceVolume(voiceVolume, delayMs);
mLastVoiceVolume = voiceVolume;
}
}
-
return NO_ERROR;
}
@@ -5798,14 +5801,10 @@
bool force)
{
ALOGVV("applyStreamVolumes() for device %08x", device);
-
- for (int stream = 0; stream < AUDIO_STREAM_FOR_POLICY_CNT; stream++) {
- checkAndSetVolume((audio_stream_type_t)stream,
- getVolumeCurves((audio_stream_type_t)stream).getVolumeIndex(device),
- outputDesc,
- device,
- delayMs,
- force);
+ for (const auto &volumeGroup : mEngine->getVolumeGroups()) {
+ auto &curves = getVolumeCurves(toVolumeSource(volumeGroup));
+ checkAndSetVolume(curves, toVolumeSource(volumeGroup),
+ curves.getVolumeIndex(device), outputDesc, device, delayMs, force);
}
}
@@ -5815,43 +5814,50 @@
int delayMs,
audio_devices_t device)
{
- for (auto stream: mEngine->getStreamTypesForProductStrategy(strategy)) {
- ALOGVV("%s() stream %d, mute %d, output ID %d", __FUNCTION__, stream, on,
- outputDesc->getId());
- setStreamMute(stream, on, outputDesc, delayMs, device);
+ std::vector<VolumeSource> sourcesToMute;
+ for (auto attributes: mEngine->getAllAttributesForProductStrategy(strategy)) {
+ ALOGVV("%s() attributes %s, mute %d, output ID %d", __func__,
+ toString(attributes).c_str(), on, outputDesc->getId());
+ VolumeSource source = toVolumeSource(attributes);
+ if (std::find(begin(sourcesToMute), end(sourcesToMute), source) == end(sourcesToMute)) {
+ sourcesToMute.push_back(source);
+ }
}
+ for (auto source : sourcesToMute) {
+ setVolumeSourceMute(source, on, outputDesc, delayMs, device);
+ }
+
}
-void AudioPolicyManager::setStreamMute(audio_stream_type_t stream,
- bool on,
- const sp<AudioOutputDescriptor>& outputDesc,
- int delayMs,
- audio_devices_t device)
+void AudioPolicyManager::setVolumeSourceMute(VolumeSource volumeSource,
+ bool on,
+ const sp<AudioOutputDescriptor>& outputDesc,
+ int delayMs,
+ audio_devices_t device)
{
if (device == AUDIO_DEVICE_NONE) {
device = outputDesc->devices().types();
}
-
- ALOGVV("setStreamMute() stream %d, mute %d, mMuteCount %d device %04x",
- stream, on, outputDesc->getMuteCount(stream), device);
- auto &curves = getVolumeCurves(stream);
+ auto &curves = getVolumeCurves(volumeSource);
if (on) {
- if (!outputDesc->isMuted(streamToVolumeSource(stream))) {
+ if (!outputDesc->isMuted(volumeSource)) {
if (curves.canBeMuted() &&
- ((stream != AUDIO_STREAM_ENFORCED_AUDIBLE) ||
- (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_NONE))) {
- checkAndSetVolume(stream, 0, outputDesc, device, delayMs);
+ (volumeSource != toVolumeSource(AUDIO_STREAM_ENFORCED_AUDIBLE) ||
+ (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) ==
+ AUDIO_POLICY_FORCE_NONE))) {
+ checkAndSetVolume(curves, volumeSource, 0, outputDesc, device, delayMs);
}
}
- // increment mMuteCount after calling checkAndSetVolume() so that volume change is not ignored
- outputDesc->incMuteCount(streamToVolumeSource(stream));
+ // increment mMuteCount after calling checkAndSetVolume() so that volume change is not
+ // ignored
+ outputDesc->incMuteCount(volumeSource);
} else {
- if (!outputDesc->isMuted(streamToVolumeSource(stream))) {
- ALOGV("setStreamMute() unmuting non muted stream!");
+ if (!outputDesc->isMuted(volumeSource)) {
+ ALOGV("%s unmuting non muted attributes!", __func__);
return;
}
- if (outputDesc->decMuteCount(streamToVolumeSource(stream)) == 0) {
- checkAndSetVolume(stream,
+ if (outputDesc->decMuteCount(volumeSource) == 0) {
+ checkAndSetVolume(curves, volumeSource,
curves.getVolumeIndex(device),
outputDesc,
device,
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 641a03a..1c98684 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -171,11 +171,7 @@
virtual status_t getMinVolumeIndexForAttributes(const audio_attributes_t &attr, int &index);
- status_t setVolumeGroupIndex(IVolumeCurves &volumeCurves, volume_group_t group, int index,
- audio_devices_t device, const audio_attributes_t attributes);
-
- status_t setVolumeCurveIndex(volume_group_t volumeGroup,
- int index,
+ status_t setVolumeCurveIndex(int index,
audio_devices_t device,
IVolumeCurves &volumeCurves);
@@ -358,6 +354,30 @@
return mDefaultOutputDevice;
}
+ std::vector<volume_group_t> getVolumeGroups() const
+ {
+ return mEngine->getVolumeGroups();
+ }
+
+ VolumeSource toVolumeSource(volume_group_t volumeGroup) const
+ {
+ return static_cast<VolumeSource>(volumeGroup);
+ }
+ VolumeSource toVolumeSource(const audio_attributes_t &attributes) const
+ {
+ return toVolumeSource(mEngine->getVolumeGroupForAttributes(attributes));
+ }
+ VolumeSource toVolumeSource(audio_stream_type_t stream) const
+ {
+ return toVolumeSource(mEngine->getVolumeGroupForStreamType(stream));
+ }
+ IVolumeCurves &getVolumeCurves(VolumeSource volumeSource)
+ {
+ auto *curves = mEngine->getVolumeCurvesForVolumeGroup(
+ static_cast<volume_group_t>(volumeSource));
+ ALOG_ASSERT(curves != nullptr, "No curves for volume source %d", volumeSource);
+ return *curves;
+ }
IVolumeCurves &getVolumeCurves(const audio_attributes_t &attr)
{
auto *curves = mEngine->getVolumeCurvesForAttributes(attr);
@@ -395,16 +415,18 @@
// compute the actual volume for a given stream according to the requested index and a particular
// device
- virtual float computeVolume(audio_stream_type_t stream,
+ virtual float computeVolume(IVolumeCurves &curves,
+ VolumeSource volumeSource,
int index,
audio_devices_t device);
// rescale volume index from srcStream within range of dstStream
int rescaleVolumeIndex(int srcIndex,
- audio_stream_type_t srcStream,
- audio_stream_type_t dstStream);
+ VolumeSource fromVolumeSource,
+ VolumeSource toVolumeSource);
// check that volume change is permitted, compute and send new volume to audio hardware
- virtual status_t checkAndSetVolume(audio_stream_type_t stream, int index,
+ virtual status_t checkAndSetVolume(IVolumeCurves &curves,
+ VolumeSource volumeSource, int index,
const sp<AudioOutputDescriptor>& outputDesc,
audio_devices_t device,
int delayMs = 0, bool force = false);
@@ -428,12 +450,20 @@
int delayMs = 0,
audio_devices_t device = AUDIO_DEVICE_NONE);
- // Mute or unmute the stream on the specified output
- void setStreamMute(audio_stream_type_t stream,
- bool on,
- const sp<AudioOutputDescriptor>& outputDesc,
- int delayMs = 0,
- audio_devices_t device = (audio_devices_t)0);
+ /**
+ * @brief setVolumeSourceMute Mute or unmute the volume source on the specified output
+ * @param volumeSource to be muted/unmute (may host legacy streams or by extension set of
+ * audio attributes)
+ * @param on true to mute, false to umute
+ * @param outputDesc on which the client following the volume group shall be muted/umuted
+ * @param delayMs
+ * @param device
+ */
+ void setVolumeSourceMute(VolumeSource volumeSource,
+ bool on,
+ const sp<AudioOutputDescriptor>& outputDesc,
+ int delayMs = 0,
+ audio_devices_t device = AUDIO_DEVICE_NONE);
audio_mode_t getPhoneState();
@@ -779,7 +809,8 @@
audio_session_t session,
audio_stream_type_t stream,
const audio_config_t *config,
- audio_output_flags_t *flags);
+ audio_output_flags_t *flags,
+ bool forceMutingHaptic = false);
/**
* @brief getInputForDevice selects an input handle for a given input device and
@@ -798,7 +829,7 @@
const audio_attributes_t &attributes,
const audio_config_base_t *config,
audio_input_flags_t flags,
- AudioMix *policyMix);
+ const sp<AudioPolicyMix> &policyMix);
// event is one of STARTING_OUTPUT, STARTING_BEACON, STOPPING_OUTPUT, STOPPING_BEACON
// returns 0 if no mute/unmute event happened, the largest latency of the device where
diff --git a/services/camera/OWNERS b/services/camera/OWNERS
index 18acfee..f48a95c 100644
--- a/services/camera/OWNERS
+++ b/services/camera/OWNERS
@@ -1,6 +1 @@
-cychen@google.com
-epeev@google.com
-etalvala@google.com
-shuzhenwang@google.com
-yinchiayeh@google.com
-zhijunhe@google.com
+include platform/frameworks/av:/camera/OWNERS
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 62ec955..51d0682 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -2180,31 +2180,37 @@
return mp;
}
-void CameraService::loadSound() {
+void CameraService::increaseSoundRef() {
+ Mutex::Autolock lock(mSoundLock);
+ mSoundRef++;
+}
+
+void CameraService::loadSoundLocked(sound_kind kind) {
ATRACE_CALL();
- Mutex::Autolock lock(mSoundLock);
- LOG1("CameraService::loadSound ref=%d", mSoundRef);
- if (mSoundRef++) return;
-
- mSoundPlayer[SOUND_SHUTTER] = newMediaPlayer("/product/media/audio/ui/camera_click.ogg");
- if (mSoundPlayer[SOUND_SHUTTER] == nullptr) {
- mSoundPlayer[SOUND_SHUTTER] = newMediaPlayer("/system/media/audio/ui/camera_click.ogg");
- }
- mSoundPlayer[SOUND_RECORDING_START] = newMediaPlayer("/product/media/audio/ui/VideoRecord.ogg");
- if (mSoundPlayer[SOUND_RECORDING_START] == nullptr) {
- mSoundPlayer[SOUND_RECORDING_START] =
+ LOG1("CameraService::loadSoundLocked ref=%d", mSoundRef);
+ if (SOUND_SHUTTER == kind && mSoundPlayer[SOUND_SHUTTER] == NULL) {
+ mSoundPlayer[SOUND_SHUTTER] = newMediaPlayer("/product/media/audio/ui/camera_click.ogg");
+ if (mSoundPlayer[SOUND_SHUTTER] == nullptr) {
+ mSoundPlayer[SOUND_SHUTTER] = newMediaPlayer("/system/media/audio/ui/camera_click.ogg");
+ }
+ } else if (SOUND_RECORDING_START == kind && mSoundPlayer[SOUND_RECORDING_START] == NULL) {
+ mSoundPlayer[SOUND_RECORDING_START] = newMediaPlayer("/product/media/audio/ui/VideoRecord.ogg");
+ if (mSoundPlayer[SOUND_RECORDING_START] == nullptr) {
+ mSoundPlayer[SOUND_RECORDING_START] =
newMediaPlayer("/system/media/audio/ui/VideoRecord.ogg");
- }
- mSoundPlayer[SOUND_RECORDING_STOP] = newMediaPlayer("/product/media/audio/ui/VideoStop.ogg");
- if (mSoundPlayer[SOUND_RECORDING_STOP] == nullptr) {
- mSoundPlayer[SOUND_RECORDING_STOP] = newMediaPlayer("/system/media/audio/ui/VideoStop.ogg");
+ }
+ } else if (SOUND_RECORDING_STOP == kind && mSoundPlayer[SOUND_RECORDING_STOP] == NULL) {
+ mSoundPlayer[SOUND_RECORDING_STOP] = newMediaPlayer("/product/media/audio/ui/VideoStop.ogg");
+ if (mSoundPlayer[SOUND_RECORDING_STOP] == nullptr) {
+ mSoundPlayer[SOUND_RECORDING_STOP] = newMediaPlayer("/system/media/audio/ui/VideoStop.ogg");
+ }
}
}
-void CameraService::releaseSound() {
+void CameraService::decreaseSoundRef() {
Mutex::Autolock lock(mSoundLock);
- LOG1("CameraService::releaseSound ref=%d", mSoundRef);
+ LOG1("CameraService::decreaseSoundRef ref=%d", mSoundRef);
if (--mSoundRef) return;
for (int i = 0; i < NUM_SOUNDS; i++) {
@@ -2220,6 +2226,7 @@
LOG1("playSound(%d)", kind);
Mutex::Autolock lock(mSoundLock);
+ loadSoundLocked(kind);
sp<MediaPlayer> player = mSoundPlayer[kind];
if (player != 0) {
player->seekTo(0);
@@ -2249,7 +2256,7 @@
mRemoteCallback = cameraClient;
- cameraService->loadSound();
+ cameraService->increaseSoundRef();
LOG1("Client::Client X (pid %d, id %d)", callingPid, mCameraId);
}
@@ -2259,7 +2266,7 @@
ALOGV("~Client");
mDestructionStarted = true;
- sCameraService->releaseSound();
+ sCameraService->decreaseSoundRef();
// unconditionally disconnect. function is idempotent
Client::disconnect();
}
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 65727ec..344dd92 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -192,10 +192,10 @@
NUM_SOUNDS
};
- void loadSound();
void playSound(sound_kind kind);
- void releaseSound();
-
+ void loadSoundLocked(sound_kind kind);
+ void decreaseSoundRef();
+ void increaseSoundRef();
/**
* Update the state of a given camera device (open/close/active/idle) with
* the camera proxy service in the system service
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index b512f2b..c7a4f2b 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -604,6 +604,7 @@
stream->v3_2.usage = Camera3Device::mapToConsumerUsage(u);
stream->v3_2.dataSpace = Camera3Device::mapToHidlDataspace(streamInfo.dataSpace);
stream->v3_2.rotation = Camera3Device::mapToStreamRotation(rotation);
+ stream->v3_2.id = -1; // Invalid stream id
stream->physicalCameraId = std::string(physicalId.string());
stream->bufferSize = 0;
}
diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
index 9fd0e8b..743c816 100644
--- a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
@@ -1177,7 +1177,7 @@
outputFormat->setInt32(KEY_BITRATE_MODE, BITRATE_MODE_CQ);
outputFormat->setInt32(KEY_QUALITY, kDefaultJpegQuality);
// Ask codec to skip timestamp check and encode all frames.
- outputFormat->setInt64("max-pts-gap-to-encoder", kNoFrameDropMaxPtsGap);
+ outputFormat->setInt64(KEY_MAX_PTS_GAP_TO_ENCODER, kNoFrameDropMaxPtsGap);
int32_t gridWidth, gridHeight, gridRows, gridCols;
if (useGrid || mUseHeic) {
diff --git a/services/camera/libcameraservice/device3/Camera3BufferManager.cpp b/services/camera/libcameraservice/device3/Camera3BufferManager.cpp
index 8c8b97a..d6bf83e 100644
--- a/services/camera/libcameraservice/device3/Camera3BufferManager.cpp
+++ b/services/camera/libcameraservice/device3/Camera3BufferManager.cpp
@@ -237,7 +237,7 @@
}
status_t Camera3BufferManager::getBufferForStream(int streamId, int streamSetId,
- sp<GraphicBuffer>* gb, int* fenceFd) {
+ sp<GraphicBuffer>* gb, int* fenceFd, bool noFreeBufferAtConsumer) {
ATRACE_CALL();
Mutex::Autolock l(mLock);
@@ -253,14 +253,19 @@
StreamSet &streamSet = mStreamSetMap.editValueFor(streamSetId);
BufferCountMap& handOutBufferCounts = streamSet.handoutBufferCountMap;
size_t& bufferCount = handOutBufferCounts.editValueFor(streamId);
+ BufferCountMap& attachedBufferCounts = streamSet.attachedBufferCountMap;
+ size_t& attachedBufferCount = attachedBufferCounts.editValueFor(streamId);
+
+ if (noFreeBufferAtConsumer) {
+ attachedBufferCount = bufferCount;
+ }
+
if (bufferCount >= streamSet.maxAllowedBufferCount) {
ALOGE("%s: bufferCount (%zu) exceeds the max allowed buffer count (%zu) of this stream set",
__FUNCTION__, bufferCount, streamSet.maxAllowedBufferCount);
return INVALID_OPERATION;
}
- BufferCountMap& attachedBufferCounts = streamSet.attachedBufferCountMap;
- size_t& attachedBufferCount = attachedBufferCounts.editValueFor(streamId);
if (attachedBufferCount > bufferCount) {
// We've already attached more buffers to this stream than we currently have
// outstanding, so have the stream just use an already-attached buffer
diff --git a/services/camera/libcameraservice/device3/Camera3BufferManager.h b/services/camera/libcameraservice/device3/Camera3BufferManager.h
index 025062e..f0de1c1 100644
--- a/services/camera/libcameraservice/device3/Camera3BufferManager.h
+++ b/services/camera/libcameraservice/device3/Camera3BufferManager.h
@@ -112,6 +112,10 @@
*
* After this call, the client takes over the ownership of this buffer if it is not freed.
*
+ * Sometimes free buffers are discarded from consumer side and the dequeueBuffer call returns
+ * TIMED_OUT, in this case calling getBufferForStream again with noFreeBufferAtConsumer set to
+ * true will notify buffer manager to update its states and also tries to allocate a new buffer.
+ *
* Return values:
*
* OK: Getting buffer for this stream was successful.
@@ -122,7 +126,9 @@
* to this buffer manager before.
* NO_MEMORY: Unable to allocate a buffer for this stream at this time.
*/
- status_t getBufferForStream(int streamId, int streamSetId, sp<GraphicBuffer>* gb, int* fenceFd);
+ status_t getBufferForStream(
+ int streamId, int streamSetId, sp<GraphicBuffer>* gb, int* fenceFd,
+ bool noFreeBufferAtConsumer = false);
/**
* This method notifies the manager that a buffer has been released by the consumer.
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 2794324..22e09e4 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -4391,8 +4391,11 @@
dst.status = BufferStatus::OK;
dst.releaseFence = nullptr;
- pushInflightBufferLocked(captureRequest->frameNumber, streamId,
- src->buffer, src->acquire_fence);
+ // Output buffers are empty when using HAL buffer manager
+ if (!mUseHalBufManager) {
+ pushInflightBufferLocked(captureRequest->frameNumber, streamId,
+ src->buffer, src->acquire_fence);
+ }
}
}
return OK;
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index 8cd575d..baba856 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -359,7 +359,18 @@
// Set dequeueBuffer/attachBuffer timeout if the consumer is not hw composer or hw texture.
// We need skip these cases as timeout will disable the non-blocking (async) mode.
if (!(isConsumedByHWComposer() || isConsumedByHWTexture())) {
- mConsumer->setDequeueTimeout(kDequeueBufferTimeout);
+ if (mUseBufferManager) {
+ // When buffer manager is handling the buffer, we should have available buffers in
+ // buffer queue before we calls into dequeueBuffer because buffer manager is tracking
+ // free buffers.
+ // There are however some consumer side feature (ImageReader::discardFreeBuffers) that
+ // can discard free buffers without notifying buffer manager. We want the timeout to
+ // happen immediately here so buffer manager can try to update its internal state and
+ // try to allocate a buffer instead of waiting.
+ mConsumer->setDequeueTimeout(0);
+ } else {
+ mConsumer->setDequeueTimeout(kDequeueBufferTimeout);
+ }
}
return OK;
@@ -526,6 +537,8 @@
if (res != OK) {
ALOGE("%s: Stream %d: Can't attach the output buffer to this surface: %s (%d)",
__FUNCTION__, mId, strerror(-res), res);
+
+ checkRetAndSetAbandonedLocked(res);
return res;
}
gotBufferFromManager = true;
@@ -562,35 +575,70 @@
mDequeueBufferLatency.add(dequeueStart, dequeueEnd);
mLock.lock();
- if (res != OK) {
+
+ if (mUseBufferManager && res == TIMED_OUT) {
+ checkRemovedBuffersLocked();
+
+ sp<GraphicBuffer> gb;
+ res = mBufferManager->getBufferForStream(
+ getId(), getStreamSetId(), &gb, fenceFd, /*noFreeBuffer*/true);
+
+ if (res == OK) {
+ // Attach this buffer to the bufferQueue: the buffer will be in dequeue state after
+ // a successful return.
+ *anb = gb.get();
+ res = mConsumer->attachBuffer(*anb);
+ gotBufferFromManager = true;
+ ALOGV("Stream %d: Attached new buffer", getId());
+
+ if (res != OK) {
+ ALOGE("%s: Stream %d: Can't attach the output buffer to this surface: %s (%d)",
+ __FUNCTION__, mId, strerror(-res), res);
+
+ checkRetAndSetAbandonedLocked(res);
+ return res;
+ }
+ } else {
+ ALOGE("%s: Stream %d: Can't get next output buffer from buffer manager:"
+ " %s (%d)", __FUNCTION__, mId, strerror(-res), res);
+ return res;
+ }
+ } else if (res != OK) {
ALOGE("%s: Stream %d: Can't dequeue next output buffer: %s (%d)",
__FUNCTION__, mId, strerror(-res), res);
- // Only transition to STATE_ABANDONED from STATE_CONFIGURED. (If it is STATE_PREPARING,
- // let prepareNextBuffer handle the error.)
- if ((res == NO_INIT || res == DEAD_OBJECT) && mState == STATE_CONFIGURED) {
- mState = STATE_ABANDONED;
- }
-
+ checkRetAndSetAbandonedLocked(res);
return res;
}
}
if (res == OK) {
- std::vector<sp<GraphicBuffer>> removedBuffers;
- res = mConsumer->getAndFlushRemovedBuffers(&removedBuffers);
- if (res == OK) {
- onBuffersRemovedLocked(removedBuffers);
-
- if (mUseBufferManager && removedBuffers.size() > 0) {
- mBufferManager->onBuffersRemoved(getId(), getStreamSetId(), removedBuffers.size());
- }
- }
+ checkRemovedBuffersLocked();
}
return res;
}
+void Camera3OutputStream::checkRemovedBuffersLocked(bool notifyBufferManager) {
+ std::vector<sp<GraphicBuffer>> removedBuffers;
+ status_t res = mConsumer->getAndFlushRemovedBuffers(&removedBuffers);
+ if (res == OK) {
+ onBuffersRemovedLocked(removedBuffers);
+
+ if (notifyBufferManager && mUseBufferManager && removedBuffers.size() > 0) {
+ mBufferManager->onBuffersRemoved(getId(), getStreamSetId(), removedBuffers.size());
+ }
+ }
+}
+
+void Camera3OutputStream::checkRetAndSetAbandonedLocked(status_t res) {
+ // Only transition to STATE_ABANDONED from STATE_CONFIGURED. (If it is
+ // STATE_PREPARING, let prepareNextBuffer handle the error.)
+ if ((res == NO_INIT || res == DEAD_OBJECT) && mState == STATE_CONFIGURED) {
+ mState = STATE_ABANDONED;
+ }
+}
+
status_t Camera3OutputStream::disconnectLocked() {
status_t res;
@@ -803,11 +851,8 @@
}
}
- std::vector<sp<GraphicBuffer>> removedBuffers;
- res = mConsumer->getAndFlushRemovedBuffers(&removedBuffers);
- if (res == OK) {
- onBuffersRemovedLocked(removedBuffers);
- }
+ // Here we assume detachBuffer is called by buffer manager so it doesn't need to be notified
+ checkRemovedBuffersLocked(/*notifyBufferManager*/false);
return res;
}
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index 2128da2..30fc2f7 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -309,6 +309,13 @@
*/
void onBuffersRemovedLocked(const std::vector<sp<GraphicBuffer>>&);
status_t detachBufferLocked(sp<GraphicBuffer>* buffer, int* fenceFd);
+ // Call this after each dequeueBuffer/attachBuffer/detachNextBuffer call to get update on
+ // removed buffers. Set notifyBufferManager to false when the call is initiated by buffer
+ // manager so buffer manager doesn't need to be notified.
+ void checkRemovedBuffersLocked(bool notifyBufferManager = true);
+
+ // Check return status of IGBP calls and set abandoned state accordingly
+ void checkRetAndSetAbandonedLocked(status_t res);
static const int32_t kDequeueLatencyBinSize = 5; // in ms
CameraLatencyHistogram mDequeueBufferLatency;
diff --git a/services/mediaanalytics/MediaAnalyticsService.cpp b/services/mediaanalytics/MediaAnalyticsService.cpp
index 4f3ac1b..06baac9 100644
--- a/services/mediaanalytics/MediaAnalyticsService.cpp
+++ b/services/mediaanalytics/MediaAnalyticsService.cpp
@@ -76,9 +76,6 @@
namespace android {
- using namespace android::base;
- using namespace android::content::pm;
-
// individual records kept in memory: age or count
// age: <= 28 hours (1 1/6 days)
// count: hard limit of # records
@@ -649,7 +646,8 @@
}
if (binder != NULL) {
- sp<IPackageManagerNative> package_mgr = interface_cast<IPackageManagerNative>(binder);
+ sp<content::pm::IPackageManagerNative> package_mgr =
+ interface_cast<content::pm::IPackageManagerNative>(binder);
binder::Status status;
std::vector<int> uids;
diff --git a/services/mediacodec/Android.bp b/services/mediacodec/Android.bp
new file mode 100644
index 0000000..25c36fa
--- /dev/null
+++ b/services/mediacodec/Android.bp
@@ -0,0 +1,62 @@
+cc_binary {
+ name: "mediaswcodec",
+ vendor_available: true,
+
+ srcs: [
+ "main_swcodecservice.cpp",
+ ],
+
+ shared_libs: [
+ "libavservices_minijail",
+ "libbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libmedia_codecserviceregistrant",
+ ],
+
+ target: {
+ vendor: {
+ exclude_shared_libs: ["libavservices_minijail"],
+ shared_libs: ["libavservices_minijail_vendor"],
+ },
+ },
+
+ header_libs: [
+ "libmedia_headers",
+ ],
+
+ init_rc: ["mediaswcodec.rc"],
+
+ required: ["mediaswcodec.policy"],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ "-Wno-error=deprecated-declarations",
+ ],
+
+ sanitize: {
+ scudo: true,
+ },
+}
+
+prebuilt_etc {
+ name: "mediaswcodec.policy",
+ sub_dir: "seccomp_policy",
+ arch: {
+ arm: {
+ src: "seccomp_policy/mediaswcodec-arm.policy",
+ },
+ arm64: {
+ src: "seccomp_policy/mediaswcodec-arm64.policy",
+ },
+ x86: {
+ src: "seccomp_policy/mediacodec-x86.policy",
+ },
+ x86_64: {
+ src: "seccomp_policy/mediacodec-x86.policy",
+ },
+ },
+ required: ["crash_dump.policy"],
+}
diff --git a/services/mediacodec/Android.mk b/services/mediacodec/Android.mk
index f78c671..9cc19a3 100644
--- a/services/mediacodec/Android.mk
+++ b/services/mediacodec/Android.mk
@@ -27,8 +27,8 @@
include $(CLEAR_VARS)
# seccomp is not required for coverage build.
ifneq ($(NATIVE_COVERAGE),true)
-LOCAL_REQUIRED_MODULES_arm := crash_dump.policy mediacodec.policy
-LOCAL_REQUIRED_MODULES_x86 := crash_dump.policy mediacodec.policy
+LOCAL_REQUIRED_MODULES_arm := mediacodec.policy
+LOCAL_REQUIRED_MODULES_x86 := mediacodec.policy
endif
LOCAL_SRC_FILES := main_codecservice.cpp
LOCAL_SHARED_LIBRARIES := \
@@ -65,74 +65,13 @@
####################################################################
-# service executable
-include $(CLEAR_VARS)
-# seccomp is not required for coverage build.
-ifneq ($(NATIVE_COVERAGE),true)
-LOCAL_REQUIRED_MODULES_arm := crash_dump.policy mediaswcodec.policy
-LOCAL_REQUIRED_MODULES_arm64 := crash_dump.policy mediaswcodec.policy
-LOCAL_REQUIRED_MODULES_x86 := crash_dump.policy mediaswcodec.policy
-LOCAL_REQUIRED_MODULES_x86_64 := crash_dump.policy mediaswcodec.policy
-endif
-
-LOCAL_SRC_FILES := \
- main_swcodecservice.cpp \
- MediaCodecUpdateService.cpp \
-
-sanitizer_runtime_libraries := $(call normalize-path-list,$(addsuffix .so,\
- $(ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
- $(UBSAN_RUNTIME_LIBRARY) \
- $(TSAN_RUNTIME_LIBRARY) \
- $(2ND_ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
- $(2ND_UBSAN_RUNTIME_LIBRARY) \
- $(2ND_TSAN_RUNTIME_LIBRARY)))
-
-# $(info Sanitizer: $(sanitizer_runtime_libraries))
-
-llndk_libraries := $(call normalize-path-list,$(addsuffix .so,\
- $(LLNDK_LIBRARIES)))
-
-# $(info LLNDK: $(llndk_libraries))
-
-LOCAL_CFLAGS := -DLINKED_LIBRARIES='"$(sanitizer_runtime_libraries):$(llndk_libraries)"'
-
-LOCAL_SHARED_LIBRARIES := \
- libavservices_minijail \
- libbase \
- libbinder \
- libcutils \
- libhidltransport \
- libhwbinder \
- liblog \
- libmedia \
- libutils \
- libziparchive \
-
-LOCAL_HEADER_LIBRARIES := \
- libnativeloader-dummy-headers \
-
-LOCAL_MODULE := mediaswcodec
-LOCAL_INIT_RC := mediaswcodec.rc
-LOCAL_SANITIZE := scudo
-ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), x86_64 arm64))
- LOCAL_MULTILIB := both
- LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
- LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)
-endif
-
-sanitizer_runtime_libraries :=
-llndk_libraries :=
-
-include $(BUILD_EXECUTABLE)
-
-####################################################################
-
# service seccomp policy
ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), x86 x86_64 arm arm64))
include $(CLEAR_VARS)
LOCAL_MODULE := mediacodec.policy
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/seccomp_policy
+LOCAL_REQUIRED_MODULES := crash_dump.policy
# mediacodec runs in 32-bit combatibility mode. For 64 bit architectures,
# use the 32 bit policy
ifdef TARGET_2ND_ARCH
@@ -149,14 +88,5 @@
####################################################################
-# sw service seccomp policy
-ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), x86 x86_64 arm arm64))
-include $(CLEAR_VARS)
-LOCAL_MODULE := mediaswcodec.policy
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/seccomp_policy
-LOCAL_SRC_FILES := seccomp_policy/mediaswcodec-$(TARGET_ARCH).policy
-include $(BUILD_PREBUILT)
-endif
include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/services/mediacodec/MediaCodecUpdateService.cpp b/services/mediacodec/MediaCodecUpdateService.cpp
deleted file mode 100644
index 50ccbce..0000000
--- a/services/mediacodec/MediaCodecUpdateService.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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_TAG "MediaCodecUpdateService"
-//#define LOG_NDEBUG 0
-
-#include <android/dlext.h>
-#include <dlfcn.h>
-#include <media/CodecServiceRegistrant.h>
-#include <nativeloader/dlext_namespaces.h>
-#include <utils/Log.h>
-#include <utils/String8.h>
-
-#include "MediaCodecUpdateService.h"
-
-namespace android {
-
-void loadFromApex(const char *libDirPath) {
- ALOGV("loadFromApex: path=%s", libDirPath);
-
- String8 libPath = String8(libDirPath) + "/libmedia_codecserviceregistrant.so";
-
- android_namespace_t *codecNs = android_create_namespace("codecs",
- nullptr, // ld_library_path
- libDirPath,
- ANDROID_NAMESPACE_TYPE_ISOLATED,
- nullptr, // permitted_when_isolated_path
- nullptr); // parent
-
- if (codecNs == nullptr) {
- ALOGE("Failed to create codec namespace");
- return;
- }
-
- String8 linked_libraries(LINKED_LIBRARIES);
- if (!android_link_namespaces(codecNs, nullptr, linked_libraries.c_str())) {
- ALOGE("Failed to link namespace");
- return;
- }
-
- const android_dlextinfo dlextinfo = {
- .flags = ANDROID_DLEXT_USE_NAMESPACE,
- .library_namespace = codecNs,
- };
-
- void *registrantLib = android_dlopen_ext(
- libPath.string(),
- RTLD_NOW | RTLD_LOCAL, &dlextinfo);
-
- if (registrantLib == nullptr) {
- ALOGE("Failed to load lib from archive: %s", dlerror());
- }
-
- RegisterCodecServicesFunc registerCodecServices =
- reinterpret_cast<RegisterCodecServicesFunc>(
- dlsym(registrantLib, "RegisterCodecServices"));
-
- if (registerCodecServices == nullptr) {
- ALOGE("Cannot register codec services -- corrupted library.");
- return;
- }
-
- registerCodecServices();
-}
-
-} // namespace android
diff --git a/services/mediacodec/MediaCodecUpdateService.h b/services/mediacodec/MediaCodecUpdateService.h
deleted file mode 100644
index 09d6dbe..0000000
--- a/services/mediacodec/MediaCodecUpdateService.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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 ANDROID_MEDIA_CODEC_UPDATE_SERVICE_H
-#define ANDROID_MEDIA_CODEC_UPDATE_SERVICE_H
-
-namespace android {
-
-void loadFromApex(const char *libDirPath);
-
-} // namespace android
-
-#endif // ANDROID_MEDIA_CODEC_UPDATE_SERVICE_H
diff --git a/services/mediacodec/main_swcodecservice.cpp b/services/mediacodec/main_swcodecservice.cpp
index 05b5695..c44be28 100644
--- a/services/mediacodec/main_swcodecservice.cpp
+++ b/services/mediacodec/main_swcodecservice.cpp
@@ -19,24 +19,26 @@
// from LOCAL_C_INCLUDES
#include "minijail.h"
-
#include <hidl/HidlTransportSupport.h>
-#include "MediaCodecUpdateService.h"
-
using namespace android;
+// kSystemSeccompPolicyPath points to the policy for the swcodecs themselves and
+// is part of the updates. kVendorSeccompPolicyPath points to any additional
+// policies that the vendor may need for the device.
static const char kSystemSeccompPolicyPath[] =
- "/system/etc/seccomp_policy/mediaswcodec.policy";
+ "/apex/com.android.media.swcodec/etc/seccomp_policy/mediaswcodec.policy";
static const char kVendorSeccompPolicyPath[] =
"/vendor/etc/seccomp_policy/mediaswcodec.policy";
// Disable Scudo's mismatch allocation check, as it is being triggered
// by some third party code.
extern "C" const char *__scudo_default_options() {
- return "DeallocationTypeMismatch=false";
+ return "DeallocationTypeMismatch=false";
}
+extern "C" void RegisterCodecServices();
+
int main(int argc __unused, char** /*argv*/)
{
LOG(INFO) << "media swcodec service starting";
@@ -45,11 +47,7 @@
::android::hardware::configureRpcThreadpool(64, false);
-#ifdef __LP64__
- loadFromApex("/apex/com.android.media.swcodec/lib64");
-#else
- loadFromApex("/apex/com.android.media.swcodec/lib");
-#endif
+ RegisterCodecServices();
::android::hardware::joinRpcThreadpool();
}
diff --git a/services/mediaextractor/Android.mk b/services/mediaextractor/Android.mk
index 661a475..fd34d5b 100644
--- a/services/mediaextractor/Android.mk
+++ b/services/mediaextractor/Android.mk
@@ -22,7 +22,6 @@
LOCAL_SRC_FILES := main_extractorservice.cpp
LOCAL_SHARED_LIBRARIES := libmedia libmediaextractorservice libbinder libutils \
liblog libandroidicu libavservices_minijail
-LOCAL_STATIC_LIBRARIES := libicuandroid_utils
LOCAL_MODULE:= mediaextractor
LOCAL_INIT_RC := mediaextractor.rc
LOCAL_C_INCLUDES := frameworks/av/media/libmedia
diff --git a/services/mediaextractor/main_extractorservice.cpp b/services/mediaextractor/main_extractorservice.cpp
index 3c15bfd..06b532d 100644
--- a/services/mediaextractor/main_extractorservice.cpp
+++ b/services/mediaextractor/main_extractorservice.cpp
@@ -15,6 +15,7 @@
** limitations under the License.
*/
+#include <aicu/AIcu.h>
#include <fcntl.h>
#include <sys/prctl.h>
#include <sys/wait.h>
@@ -29,7 +30,6 @@
#include <utils/misc.h>
// from LOCAL_C_INCLUDES
-#include "IcuUtils.h"
#include "MediaExtractorService.h"
#include "MediaUtils.h"
#include "minijail.h"
@@ -64,7 +64,7 @@
SetUpMinijail(kSystemSeccompPolicyPath, kVendorSeccompPolicyPath);
- InitializeIcuOrDie();
+ AIcu_initializeIcuOrDie();
strcpy(argv[0], "media.extractor");
sp<ProcessState> proc(ProcessState::self());
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy b/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
index 87018ed..964acf4 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
@@ -14,6 +14,7 @@
setpriority: 1
sigaltstack: 1
openat: 1
+open: 1
clone: 1
read: 1
clock_gettime: 1
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy b/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
index d739ba1..56ad8df 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
@@ -11,6 +11,7 @@
mmap2: 1
madvise: 1
openat: 1
+open: 1
clock_gettime: 1
writev: 1
brk: 1