Merge "Fix CFI issues with extractor threading" into main
diff --git a/camera/Android.bp b/camera/Android.bp
index 25b5e2c..71c1673 100644
--- a/camera/Android.bp
+++ b/camera/Android.bp
@@ -82,6 +82,8 @@
include_dirs: [
"frameworks/native/aidl/gui",
"frameworks/native/libs/permission/aidl",
+ "hardware/interfaces/common/fmq/aidl",
+ "hardware/interfaces/common/aidl",
],
},
@@ -112,6 +114,8 @@
],
shared_libs: [
+ "android.hardware.common.fmq-V1-cpp",
+ "android.hardware.common-V2-cpp",
"camera_platform_flags_c_lib",
"framework-permission-aidl-cpp",
"lib-platform-compat-native-api",
@@ -136,6 +140,8 @@
],
export_shared_lib_headers: [
"framework-permission-aidl-cpp",
+ "android.hardware.common.fmq-V1-cpp",
+ "android.hardware.common-V2-cpp",
"libcamera_metadata",
"libgui",
"libnativewindow",
@@ -187,6 +193,7 @@
"aidl/android/hardware/camera2/ICameraInjectionCallback.aidl",
"aidl/android/hardware/camera2/ICameraInjectionSession.aidl",
"aidl/android/hardware/camera2/ICameraOfflineSession.aidl",
+ "aidl/android/hardware/camera2/CameraMetadataInfo.aidl",
],
path: "aidl",
}
diff --git a/camera/CaptureResult.cpp b/camera/CaptureResult.cpp
index 9ff2578..254984f 100644
--- a/camera/CaptureResult.cpp
+++ b/camera/CaptureResult.cpp
@@ -98,7 +98,6 @@
status_t res;
mPhysicalCameraId = "";
- mPhysicalCameraMetadata.clear();
String16 physicalCameraId;
if ((res = parcel->readString16(&physicalCameraId)) != OK) {
@@ -107,10 +106,11 @@
}
mPhysicalCameraId = toStdString(physicalCameraId);
- if ((res = mPhysicalCameraMetadata.readFromParcel(parcel)) != OK) {
+ if ((res = mCameraMetadataInfo.readFromParcel(parcel)) != OK) {
ALOGE("%s: Failed to read metadata from parcel: %d", __FUNCTION__, res);
return res;
}
+
return OK;
}
@@ -121,11 +121,13 @@
__FUNCTION__, res);
return res;
}
- if ((res = mPhysicalCameraMetadata.writeToParcel(parcel)) != OK) {
+
+ if ((res = mCameraMetadataInfo.writeToParcel(parcel)) != OK) {
ALOGE("%s: Failed to write physical camera metadata to parcel: %d",
__FUNCTION__, res);
return res;
}
+
return OK;
}
@@ -178,20 +180,12 @@
}
for (int32_t i = 0; i < physicalMetadataCount; i++) {
- String16 cameraId;
- if ((res = parcel->readString16(&cameraId)) != OK) {
- ALOGE("%s: Failed to read camera id: %d", __FUNCTION__, res);
+ PhysicalCaptureResultInfo result;
+ if ((res = result.readFromParcel(parcel)) != OK) {
+ ALOGE("%s: Failed to read physical result from parcel: %d", __FUNCTION__, res);
return res;
}
-
- CameraMetadata physicalMetadata;
- if ((res = physicalMetadata.readFromParcel(parcel)) != OK) {
- ALOGE("%s: Failed to read metadata from parcel: %d", __FUNCTION__, res);
- return res;
- }
-
- mPhysicalMetadatas.emplace(mPhysicalMetadatas.end(), toStdString(cameraId),
- physicalMetadata);
+ mPhysicalMetadatas.emplace(mPhysicalMetadatas.end(), result);
}
ALOGV("%s: Read physical metadata from parcel", __FUNCTION__);
@@ -232,13 +226,8 @@
return BAD_VALUE;
}
for (const auto& physicalMetadata : mPhysicalMetadatas) {
- if ((res = parcel->writeString16(toString16(physicalMetadata.mPhysicalCameraId))) != OK) {
- ALOGE("%s: Failed to write physical camera ID to parcel: %d",
- __FUNCTION__, res);
- return res;
- }
- if ((res = physicalMetadata.mPhysicalCameraMetadata.writeToParcel(parcel)) != OK) {
- ALOGE("%s: Failed to write physical camera metadata to parcel: %d",
+ if ((res = physicalMetadata.writeToParcel(parcel)) != OK) {
+ ALOGE("%s: Failed to write physicalMetadata to parcel: %d",
__FUNCTION__, res);
return res;
}
diff --git a/camera/aidl/android/hardware/camera2/CameraMetadataInfo.aidl b/camera/aidl/android/hardware/camera2/CameraMetadataInfo.aidl
new file mode 100644
index 0000000..74c207e
--- /dev/null
+++ b/camera/aidl/android/hardware/camera2/CameraMetadataInfo.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2;
+
+import android.hardware.camera2.impl.CameraMetadataNative;
+
+/** @hide */
+union CameraMetadataInfo {
+ long fmqSize;
+ CameraMetadataNative metadata;
+}
\ No newline at end of file
diff --git a/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl b/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl
index 49e9920..68e6354 100644
--- a/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl
+++ b/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl
@@ -16,6 +16,7 @@
package android.hardware.camera2;
+import android.hardware.camera2.CameraMetadataInfo;
import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.impl.CaptureResultExtras;
import android.hardware.camera2.impl.PhysicalCaptureResultInfo;
@@ -36,7 +37,7 @@
oneway void onDeviceError(int errorCode, in CaptureResultExtras resultExtras);
oneway void onDeviceIdle();
oneway void onCaptureStarted(in CaptureResultExtras resultExtras, long timestamp);
- oneway void onResultReceived(in CameraMetadataNative result,
+ oneway void onResultReceived(in CameraMetadataInfo resultInfo,
in CaptureResultExtras resultExtras,
in PhysicalCaptureResultInfo[] physicalCaptureResultInfos);
oneway void onPrepared(int streamId);
diff --git a/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl b/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
index c1da126..a9191eb 100644
--- a/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
+++ b/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
@@ -23,6 +23,8 @@
import android.hardware.camera2.params.OutputConfiguration;
import android.hardware.camera2.params.SessionConfiguration;
import android.hardware.camera2.utils.SubmitInfo;
+import android.hardware.common.fmq.MQDescriptor;
+import android.hardware.common.fmq.SynchronizedReadWrite;
import android.view.Surface;
/** @hide */
@@ -173,6 +175,7 @@
void finalizeOutputConfigurations(int streamId, in OutputConfiguration outputConfiguration);
+ MQDescriptor<byte, SynchronizedReadWrite> getCaptureResultMetadataQueue();
// Keep in sync with public API in
// frameworks/base/core/java/android/hardware/camera2/CameraDevice.java
diff --git a/camera/camera2/CaptureRequest.cpp b/camera/camera2/CaptureRequest.cpp
index 071f34e..d2fcde6 100644
--- a/camera/camera2/CaptureRequest.cpp
+++ b/camera/camera2/CaptureRequest.cpp
@@ -24,6 +24,7 @@
#include <camera/StringUtils.h>
#include <binder/Parcel.h>
+#include <gui/Flags.h> // remove with WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
#include <gui/Surface.h>
#include <gui/view/Surface.h>
@@ -112,11 +113,14 @@
return err;
}
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+ sp<Surface> surface = surfaceShim.toSurface();
+#else
sp<Surface> surface;
if (surfaceShim.graphicBufferProducer != NULL) {
surface = new Surface(surfaceShim.graphicBufferProducer);
}
-
+#endif
mSurfaceList.push_back(surface);
}
@@ -206,9 +210,13 @@
parcel->writeString16(String16("android.view.Surface"));
// Surface.writeToParcel
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+ view::Surface surfaceShim = view::Surface::fromSurface(mSurfaceList[i]);
+#else
view::Surface surfaceShim;
surfaceShim.name = String16("unknown_name");
surfaceShim.graphicBufferProducer = mSurfaceList[i]->getIGraphicBufferProducer();
+#endif
if ((err = surfaceShim.writeToParcel(parcel)) != OK) {
ALOGE("%s: Failed to write output target Surface %d to parcel: %s (%d)",
__FUNCTION__, i, strerror(-err), err);
diff --git a/camera/camera2/OutputConfiguration.cpp b/camera/camera2/OutputConfiguration.cpp
index a89d7ca..f67214b 100644
--- a/camera/camera2/OutputConfiguration.cpp
+++ b/camera/camera2/OutputConfiguration.cpp
@@ -37,9 +37,8 @@
const int OutputConfiguration::ROTATION_0 = 0;
const int OutputConfiguration::INVALID_SET_ID = -1;
-const std::vector<sp<IGraphicBufferProducer>>&
- OutputConfiguration::getGraphicBufferProducers() const {
- return mGbps;
+const std::vector<ParcelableSurfaceType>& OutputConfiguration::getSurfaces() const {
+ return mSurfaces;
}
int OutputConfiguration::getRotation() const {
@@ -102,24 +101,23 @@
return mMirrorMode;
}
-int OutputConfiguration::getMirrorMode(sp<IGraphicBufferProducer> surface) const {
+int OutputConfiguration::getMirrorMode(ParcelableSurfaceType surface) const {
if (!flags::mirror_mode_shared_surfaces()) {
return mMirrorMode;
}
- if (mGbps.size() != mMirrorModeForProducers.size()) {
- ALOGE("%s: mGbps size doesn't match mMirrorModeForProducers: %zu vs %zu",
- __FUNCTION__, mGbps.size(), mMirrorModeForProducers.size());
+ if (mSurfaces.size() != mMirrorModeForProducers.size()) {
+ ALOGE("%s: mSurfaces size doesn't match mMirrorModeForProducers: %zu vs %zu",
+ __FUNCTION__, mSurfaces.size(), mMirrorModeForProducers.size());
return mMirrorMode;
}
// Use per-producer mirror mode if available.
- for (size_t i = 0; i < mGbps.size(); i++) {
- if (mGbps[i] == surface) {
+ for (size_t i = 0; i < mSurfaces.size(); i++) {
+ if (mSurfaces[i] == surface) {
return mMirrorModeForProducers[i];
}
}
-
// For surface that doesn't belong to this output configuration, use
// mMirrorMode as default.
ALOGW("%s: Surface doesn't belong to this OutputConfiguration!", __FUNCTION__);
@@ -144,9 +142,9 @@
bool OutputConfiguration::isComplete() const {
return !((mSurfaceType == SURFACE_TYPE_MEDIA_RECORDER ||
- mSurfaceType == SURFACE_TYPE_MEDIA_CODEC ||
- mSurfaceType == SURFACE_TYPE_IMAGE_READER) &&
- mGbps.empty());
+ mSurfaceType == SURFACE_TYPE_MEDIA_CODEC ||
+ mSurfaceType == SURFACE_TYPE_IMAGE_READER) &&
+ mSurfaces.empty());
}
OutputConfiguration::OutputConfiguration() :
@@ -348,7 +346,7 @@
ALOGV("%s: OutputConfiguration: %p, name %s", __FUNCTION__,
surface.graphicBufferProducer.get(),
toString8(surface.name).c_str());
- mGbps.push_back(surface.graphicBufferProducer);
+ mSurfaces.push_back(flagtools::toParcelableSurfaceType(surface));
}
mSensorPixelModesUsed = std::move(sensorPixelModesUsed);
@@ -369,10 +367,10 @@
return err;
}
-OutputConfiguration::OutputConfiguration(sp<IGraphicBufferProducer>& gbp, int rotation,
+OutputConfiguration::OutputConfiguration(ParcelableSurfaceType& surface, int rotation,
const std::string& physicalId,
int surfaceSetID, bool isShared) {
- mGbps.push_back(gbp);
+ mSurfaces.push_back(surface);
mRotation = rotation;
mSurfaceSetID = surfaceSetID;
mIsDeferred = false;
@@ -392,17 +390,17 @@
}
OutputConfiguration::OutputConfiguration(
- const std::vector<sp<IGraphicBufferProducer>>& gbps,
+ const std::vector<ParcelableSurfaceType>& surfaces,
int rotation, const std::string& physicalCameraId, int surfaceSetID, int surfaceType,
int width, int height, bool isShared)
- : mGbps(gbps), mRotation(rotation), mSurfaceSetID(surfaceSetID), mSurfaceType(surfaceType),
- mWidth(width), mHeight(height), mIsDeferred(false), mIsShared(isShared),
- mPhysicalCameraId(physicalCameraId), mIsMultiResolution(false),
+ : mSurfaces(surfaces), mRotation(rotation), mSurfaceSetID(surfaceSetID),
+ mSurfaceType(surfaceType), mWidth(width), mHeight(height), mIsDeferred(false),
+ mIsShared(isShared), mPhysicalCameraId(physicalCameraId), mIsMultiResolution(false),
mDynamicRangeProfile(ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD),
mColorSpace(ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED),
mStreamUseCase(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT),
mTimestampBase(TIMESTAMP_BASE_DEFAULT),
- mMirrorMode(MIRROR_MODE_AUTO), mMirrorModeForProducers(gbps.size(), mMirrorMode),
+ mMirrorMode(MIRROR_MODE_AUTO), mMirrorModeForProducers(surfaces.size(), mMirrorMode),
mUseReadoutTimestamp(false), mFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
mDataspace(0), mUsage(0) { }
@@ -432,14 +430,18 @@
err = parcel->writeInt32(mIsShared ? 1 : 0);
if (err != OK) return err;
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+ err = parcel->writeParcelableVector(mSurfaces);
+#else
std::vector<view::Surface> surfaceShims;
- for (auto& gbp : mGbps) {
+ for (auto& gbp : mSurfaces) {
view::Surface surfaceShim;
surfaceShim.name = String16("unknown_name"); // name of surface
surfaceShim.graphicBufferProducer = gbp;
surfaceShims.push_back(surfaceShim);
}
err = parcel->writeParcelableVector(surfaceShims);
+#endif
if (err != OK) return err;
String16 physicalCameraId = toString16(mPhysicalCameraId);
@@ -513,10 +515,9 @@
return false;
}
-bool OutputConfiguration::gbpsEqual(const OutputConfiguration& other) const {
- const std::vector<sp<IGraphicBufferProducer> >& otherGbps =
- other.getGraphicBufferProducers();
- return simpleVectorsEqual(otherGbps, mGbps);
+bool OutputConfiguration::surfacesEqual(const OutputConfiguration& other) const {
+ const std::vector<ParcelableSurfaceType>& otherSurfaces = other.getSurfaces();
+ return simpleVectorsEqual(otherSurfaces, mSurfaces);
}
bool OutputConfiguration::sensorPixelModesUsedEqual(const OutputConfiguration& other) const {
@@ -527,7 +528,6 @@
bool OutputConfiguration::mirrorModesEqual(const OutputConfiguration& other) const {
const std::vector<int>& otherMirrorModes = other.getMirrorModes();
return simpleVectorsEqual(otherMirrorModes, mMirrorModeForProducers);
-
}
bool OutputConfiguration::sensorPixelModesUsedLessThan(const OutputConfiguration& other) const {
@@ -540,17 +540,16 @@
return simpleVectorsLessThan(mMirrorModeForProducers, otherMirrorModes);
}
-bool OutputConfiguration::gbpsLessThan(const OutputConfiguration& other) const {
- const std::vector<sp<IGraphicBufferProducer> >& otherGbps =
- other.getGraphicBufferProducers();
+bool OutputConfiguration::surfacesLessThan(const OutputConfiguration& other) const {
+ const std::vector<ParcelableSurfaceType>& otherSurfaces = other.getSurfaces();
- if (mGbps.size() != otherGbps.size()) {
- return mGbps.size() < otherGbps.size();
+ if (mSurfaces.size() != otherSurfaces.size()) {
+ return mSurfaces.size() < otherSurfaces.size();
}
- for (size_t i = 0; i < mGbps.size(); i++) {
- if (mGbps[i] != otherGbps[i]) {
- return mGbps[i] < otherGbps[i];
+ for (size_t i = 0; i < mSurfaces.size(); i++) {
+ if (mSurfaces[i] != otherSurfaces[i]) {
+ return mSurfaces[i] < otherSurfaces[i];
}
}
diff --git a/camera/camera_platform.aconfig b/camera/camera_platform.aconfig
index 2feebb4..5682ad2 100644
--- a/camera/camera_platform.aconfig
+++ b/camera/camera_platform.aconfig
@@ -183,6 +183,13 @@
flag {
namespace: "camera_platform"
+ name: "depth_jpeg_extensions"
+ description: "Add Depth Jpeg extension output support"
+ bug: "362788689"
+}
+
+flag {
+ namespace: "camera_platform"
name: "mirror_mode_shared_surfaces"
is_exported: true
description: "Support setting and getting mirror mode for shared surfaces"
@@ -256,3 +263,13 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ namespace: "camera_platform"
+ name: "fmq_metadata"
+ description: "Allow CameraMetadata transfer for ndk / sdk clients."
+ bug: "362791857"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
\ No newline at end of file
diff --git a/camera/include/camera/CameraMetadata.h b/camera/include/camera/CameraMetadata.h
index 2903dfb..10ecc4f 100644
--- a/camera/include/camera/CameraMetadata.h
+++ b/camera/include/camera/CameraMetadata.h
@@ -247,6 +247,38 @@
*/
metadata_vendor_id_t getVendorId() const;
+ // Needed for auto-generated code if CameraMetadata is used in
+ // parcelables in .aidl files.
+ inline bool operator == (const CameraMetadata& rhs) const {
+ return mBuffer == rhs.mBuffer;
+ }
+
+ inline bool operator < (const CameraMetadata& rhs) const {
+ return mBuffer < rhs.mBuffer;
+ }
+
+ inline bool operator != (const CameraMetadata& rhs) const {
+ return !(*this == rhs);
+ }
+
+ inline bool operator > (const CameraMetadata& rhs) const {
+ return rhs < *this;
+ }
+
+ inline bool operator >= (const CameraMetadata& rhs) const {
+ return !(*this < rhs);
+ }
+
+ inline bool operator <= (const CameraMetadata& rhs) const {
+ return !(rhs < *this);
+ }
+
+ inline std::string toString() const {
+ std::string descStr = "CameraMetadata";
+ return descStr;
+ }
+
+
private:
camera_metadata_t *mBuffer;
mutable bool mLocked;
@@ -265,7 +297,6 @@
* Resize metadata buffer if needed by reallocating it and copying it over.
*/
status_t resizeIfNeeded(size_t extraEntries, size_t extraData);
-
};
namespace hardware {
diff --git a/camera/include/camera/CaptureResult.h b/camera/include/camera/CaptureResult.h
index e08c9ca..cc6b529 100644
--- a/camera/include/camera/CaptureResult.h
+++ b/camera/include/camera/CaptureResult.h
@@ -20,7 +20,7 @@
#include <utils/RefBase.h>
#include <binder/Parcelable.h>
#include <camera/CameraMetadata.h>
-
+#include <android/hardware/camera2/CameraMetadataInfo.h>
namespace android {
@@ -145,19 +145,26 @@
};
struct PhysicalCaptureResultInfo : public android::Parcelable {
-
+ using CameraMetadataInfo = android::hardware::camera2::CameraMetadataInfo;
PhysicalCaptureResultInfo()
: mPhysicalCameraId(),
- mPhysicalCameraMetadata() {
+ mCameraMetadataInfo() {
}
PhysicalCaptureResultInfo(const std::string& cameraId,
const CameraMetadata& cameraMetadata)
- : mPhysicalCameraId(cameraId),
- mPhysicalCameraMetadata(cameraMetadata) {
+ : mPhysicalCameraId(cameraId) {
+ mCameraMetadataInfo.set<CameraMetadataInfo::metadata>(cameraMetadata);
+ }
+
+ PhysicalCaptureResultInfo(const std::string& cameraId,
+ uint64_t fmqSize)
+ : mPhysicalCameraId(cameraId) {
+ mCameraMetadataInfo.set<CameraMetadataInfo::fmqSize>(fmqSize);
}
std::string mPhysicalCameraId;
- CameraMetadata mPhysicalCameraMetadata;
+
+ CameraMetadataInfo mCameraMetadataInfo;
virtual status_t readFromParcel(const android::Parcel* parcel) override;
virtual status_t writeToParcel(android::Parcel* parcel) const override;
diff --git a/camera/include/camera/android/hardware/ICamera.h b/camera/include/camera/android/hardware/ICamera.h
index eb887fb..3c1670a 100644
--- a/camera/include/camera/android/hardware/ICamera.h
+++ b/camera/include/camera/android/hardware/ICamera.h
@@ -34,8 +34,13 @@
class ICameraClient;
-class ICamera: public android::IInterface
-{
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+typedef Surface ProducerType;
+#else
+typedef IGraphicBufferProducer ProducerType;
+#endif
+
+class ICamera : public android::IInterface {
/**
* Keep up-to-date with ICamera.aidl in frameworks/base
*/
diff --git a/camera/include/camera/camera2/OutputConfiguration.h b/camera/include/camera/camera2/OutputConfiguration.h
index 671d065..13bedb3 100644
--- a/camera/include/camera/camera2/OutputConfiguration.h
+++ b/camera/include/camera/camera2/OutputConfiguration.h
@@ -19,7 +19,12 @@
#include <string>
+#include <gui/Flags.h> // remove with WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+#include <gui/view/Surface.h>
+#else
#include <gui/IGraphicBufferProducer.h>
+#endif
#include <binder/Parcelable.h>
namespace android {
@@ -59,7 +64,7 @@
MIRROR_MODE_V = 3,
};
- const std::vector<sp<IGraphicBufferProducer>>& getGraphicBufferProducers() const;
+ const std::vector<ParcelableSurfaceType>& getSurfaces() const;
int getRotation() const;
int getSurfaceSetID() const;
int getSurfaceType() const;
@@ -73,7 +78,7 @@
bool isMultiResolution() const;
int64_t getStreamUseCase() const;
int getTimestampBase() const;
- int getMirrorMode(sp<IGraphicBufferProducer> surface) const;
+ int getMirrorMode(ParcelableSurfaceType surface) const;
int getMirrorMode() const;
bool useReadoutTimestamp() const;
int getFormat() const;
@@ -100,11 +105,11 @@
// getSurfaceSetID will be INVALID_SET_ID if error occurred
OutputConfiguration(const android::Parcel& parcel);
- OutputConfiguration(sp<IGraphicBufferProducer>& gbp, int rotation,
+ OutputConfiguration(ParcelableSurfaceType& surface, int rotation,
const std::string& physicalCameraId,
int surfaceSetID = INVALID_SET_ID, bool isShared = false);
- OutputConfiguration(const std::vector<sp<IGraphicBufferProducer>>& gbps,
+ OutputConfiguration(const std::vector<ParcelableSurfaceType>& surfaces,
int rotation, const std::string& physicalCameraId,
int surfaceSetID = INVALID_SET_ID,
int surfaceType = SURFACE_TYPE_UNKNOWN, int width = 0,
@@ -121,7 +126,7 @@
mHeight == other.mHeight &&
mIsDeferred == other.mIsDeferred &&
mIsShared == other.mIsShared &&
- gbpsEqual(other) &&
+ surfacesEqual(other) &&
mPhysicalCameraId == other.mPhysicalCameraId &&
mIsMultiResolution == other.mIsMultiResolution &&
sensorPixelModesUsedEqual(other) &&
@@ -201,18 +206,21 @@
if (mUsage != other.mUsage) {
return mUsage < other.mUsage;
}
- return gbpsLessThan(other);
+ return surfacesLessThan(other);
}
bool operator > (const OutputConfiguration& other) const {
return (*this != other && !(*this < other));
}
- bool gbpsEqual(const OutputConfiguration& other) const;
+ bool surfacesEqual(const OutputConfiguration& other) const;
bool sensorPixelModesUsedEqual(const OutputConfiguration& other) const;
bool sensorPixelModesUsedLessThan(const OutputConfiguration& other) const;
- bool gbpsLessThan(const OutputConfiguration& other) const;
- void addGraphicProducer(sp<IGraphicBufferProducer> gbp) {mGbps.push_back(gbp);}
+ bool surfacesLessThan(const OutputConfiguration& other) const;
+ void addSurface(ParcelableSurfaceType surface) { mSurfaces.push_back(surface); }
+#if not WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+ void addGraphicProducer(sp<IGraphicBufferProducer> gbp) {addSurface(gbp);}
+#endif
bool mirrorModesEqual(const OutputConfiguration& other) const;
bool mirrorModesLessThan(const OutputConfiguration& other) const;
const std::vector<int32_t>& getMirrorModes() const {return mMirrorModeForProducers;}
@@ -239,7 +247,7 @@
}
private:
- std::vector<sp<IGraphicBufferProducer>> mGbps;
+ std::vector<ParcelableSurfaceType> mSurfaces;
int mRotation;
int mSurfaceSetID;
int mSurfaceType;
diff --git a/camera/ndk/Android.bp b/camera/ndk/Android.bp
index 508808f..fc1e547 100644
--- a/camera/ndk/Android.bp
+++ b/camera/ndk/Android.bp
@@ -79,6 +79,8 @@
shared_libs: [
"android.companion.virtual.virtualdevice_aidl-cpp",
"android.companion.virtualdevice.flags-aconfig-cc",
+ "android.hardware.common-V2-cpp",
+ "android.hardware.common.fmq-V1-cpp",
"camera_platform_flags_c_lib",
"framework-permission-aidl-cpp",
"libandroid_runtime",
@@ -86,6 +88,7 @@
"libcamera_client",
"libcamera_metadata",
"libcutils",
+ "libfmq",
"libgui",
"liblog",
"libmediandk",
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index aed740f..4d21467 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -37,6 +37,8 @@
namespace android {
namespace acam {
+using android::hardware::common::fmq::MQDescriptor;
+
// Static member definitions
const char* CameraDevice::kContextKey = "Context";
const char* CameraDevice::kDeviceKey = "Device";
@@ -231,25 +233,27 @@
SessionConfiguration sessionConfiguration(0 /*inputWidth*/, 0 /*inputHeight*/,
-1 /*inputFormat*/, CAMERA3_STREAM_CONFIGURATION_NORMAL_MODE);
for (const auto& output : sessionOutputContainer->mOutputs) {
- sp<IGraphicBufferProducer> iGBP(nullptr);
- ret = getIGBPfromAnw(output.mWindow, iGBP);
+ sp<SurfaceType> surface(nullptr);
+ ret = getSurfacefromAnw(output.mWindow, surface);
if (ret != ACAMERA_OK) {
ALOGE("Camera device %s failed to extract graphic producer from native window",
getId());
return ret;
}
- OutputConfiguration outConfig(iGBP, output.mRotation, output.mPhysicalCameraId,
+ ParcelableSurfaceType pSurface = flagtools::convertSurfaceTypeToParcelable(surface);
+ OutputConfiguration outConfig(pSurface, output.mRotation, output.mPhysicalCameraId,
OutputConfiguration::INVALID_SET_ID, true);
for (auto& anw : output.mSharedWindows) {
- ret = getIGBPfromAnw(anw, iGBP);
+ ret = getSurfacefromAnw(anw, surface);
if (ret != ACAMERA_OK) {
ALOGE("Camera device %s failed to extract graphic producer from native window",
getId());
return ret;
}
- outConfig.addGraphicProducer(iGBP);
+ pSurface = flagtools::convertSurfaceTypeToParcelable(surface);
+ outConfig.addSurface(pSurface);
}
sessionConfiguration.addOutputConfiguration(outConfig);
@@ -295,25 +299,27 @@
return ACAMERA_ERROR_INVALID_PARAMETER;
}
- sp<IGraphicBufferProducer> iGBP(nullptr);
- ret = getIGBPfromAnw(output->mWindow, iGBP);
+ sp<SurfaceType> surface(nullptr);
+ ret = getSurfacefromAnw(output->mWindow, surface);
if (ret != ACAMERA_OK) {
ALOGE("Camera device %s failed to extract graphic producer from native window",
getId());
return ret;
}
- OutputConfiguration outConfig(iGBP, output->mRotation, output->mPhysicalCameraId,
- OutputConfiguration::INVALID_SET_ID, true);
+ ParcelableSurfaceType pSurface = flagtools::convertSurfaceTypeToParcelable(surface);
+ OutputConfiguration outConfig(pSurface, output->mRotation, output->mPhysicalCameraId,
+ OutputConfiguration::INVALID_SET_ID, true);
for (auto& anw : output->mSharedWindows) {
- ret = getIGBPfromAnw(anw, iGBP);
+ ret = getSurfacefromAnw(anw, surface);
if (ret != ACAMERA_OK) {
ALOGE("Camera device %s failed to extract graphic producer from native window",
getId());
return ret;
}
- outConfig.addGraphicProducer(iGBP);
+ pSurface = flagtools::convertSurfaceTypeToParcelable(surface);
+ outConfig.addSurface(pSurface);
}
auto remoteRet = mRemote->updateOutputConfiguration(streamId, outConfig);
@@ -427,9 +433,9 @@
for (const auto& kvPair : mConfiguredOutputs) {
int streamId = kvPair.first;
const OutputConfiguration& outConfig = kvPair.second.second;
- const auto& gbps = outConfig.getGraphicBufferProducers();
- for (int surfaceId = 0; surfaceId < (int) gbps.size(); surfaceId++) {
- if (gbps[surfaceId] == surface->getIGraphicBufferProducer()) {
+ const auto& surfaces = outConfig.getSurfaces();
+ for (int surfaceId = 0; surfaceId < (int)surfaces.size(); surfaceId++) {
+ if (surfaces[surfaceId] == flagtools::surfaceToSurfaceType(surface)) {
found = true;
req->mStreamIdxList.push_back(streamId);
req->mSurfaceIdxList.push_back(surfaceId);
@@ -634,16 +640,13 @@
return ACAMERA_OK;
}
-camera_status_t
-CameraDevice::getIGBPfromAnw(
- ANativeWindow* anw,
- sp<IGraphicBufferProducer>& out) {
+camera_status_t CameraDevice::getSurfacefromAnw(ANativeWindow* anw, sp<SurfaceType>& out) {
sp<Surface> surface;
camera_status_t ret = getSurfaceFromANativeWindow(anw, surface);
if (ret != ACAMERA_OK) {
return ret;
}
- out = surface->getIGraphicBufferProducer();
+ out = flagtools::surfaceToSurfaceType(surface);
return ACAMERA_OK;
}
@@ -681,14 +684,16 @@
std::set<std::pair<ANativeWindow*, OutputConfiguration>> outputSet;
for (const auto& outConfig : outputs->mOutputs) {
ANativeWindow* anw = outConfig.mWindow;
- sp<IGraphicBufferProducer> iGBP(nullptr);
- ret = getIGBPfromAnw(anw, iGBP);
+ sp<SurfaceType> surface(nullptr);
+ ret = getSurfacefromAnw(anw, surface);
if (ret != ACAMERA_OK) {
return ret;
}
+ ParcelableSurfaceType pSurface = flagtools::convertSurfaceTypeToParcelable(surface);
outputSet.insert(std::make_pair(
- anw, OutputConfiguration(iGBP, outConfig.mRotation, outConfig.mPhysicalCameraId,
- OutputConfiguration::INVALID_SET_ID, outConfig.mIsShared)));
+ anw,
+ OutputConfiguration(pSurface, outConfig.mRotation, outConfig.mPhysicalCameraId,
+ OutputConfiguration::INVALID_SET_ID, outConfig.mIsShared)));
}
auto addSet = outputSet;
std::vector<int> deleteList;
@@ -788,6 +793,27 @@
mRemote = remote;
}
+bool CameraDevice::setDeviceMetadataQueues() {
+ if (mRemote == nullptr) {
+ ALOGE("mRemote must not be null while trying to fetch metadata queues");
+ return false;
+ }
+ MQDescriptor<int8_t, SynchronizedReadWrite> resMqDescriptor;
+ binder::Status ret = mRemote->getCaptureResultMetadataQueue(&resMqDescriptor);
+ if (!ret.isOk()) {
+ ALOGE("Transaction error trying to get capture result metadata queue");
+ return false;
+ }
+ mCaptureResultMetadataQueue = std::make_unique<ResultMetadataQueue>(resMqDescriptor);
+ if (!mCaptureResultMetadataQueue->isValid()) {
+ ALOGE("Empty fmq from cameraserver");
+ mCaptureResultMetadataQueue = nullptr;
+ return false;
+ }
+
+ return true;
+}
+
camera_status_t
CameraDevice::checkCameraClosedOrErrorLocked() const {
if (mRemote == nullptr) {
@@ -885,10 +911,14 @@
return;
}
- const auto& gbps = outputPairIt->second.second.getGraphicBufferProducers();
- for (const auto& outGbp : gbps) {
+ const auto& outSurfaces = outputPairIt->second.second.getSurfaces();
+ for (const auto& outSurface : outSurfaces) {
for (const auto& surface : request->mSurfaceList) {
- if (surface->getIGraphicBufferProducer() == outGbp) {
+ if ( outSurface == surface
+#if not WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+ ->getIGraphicBufferProducer()
+#endif
+ ) {
ANativeWindow* anw = static_cast<ANativeWindow*>(surface.get());
ALOGV("Camera %s Lost output buffer for ANW %p frame %" PRId64,
getId(), anw, frameNumber);
@@ -1247,7 +1277,9 @@
String8 physicalId8 = toString8(physicalResultInfo[i].mPhysicalCameraId);
physicalCameraIds.push_back(physicalId8.c_str());
- CameraMetadata clone = physicalResultInfo[i].mPhysicalCameraMetadata;
+ CameraMetadata clone =
+ physicalResultInfo[i].
+ mCameraMetadataInfo.get<CameraMetadataInfo::metadata>();
clone.update(ANDROID_SYNC_FRAME_NUMBER,
&physicalResult->mFrameNumber, /*data_count*/1);
sp<ACameraMetadata> metadata =
@@ -1777,7 +1809,7 @@
binder::Status
CameraDevice::ServiceCallback::onResultReceived(
- const CameraMetadata& metadata,
+ const CameraMetadataInfo &resultMetadata,
const CaptureResultExtras& resultExtras,
const std::vector<PhysicalCaptureResultInfo>& physicalResultInfos) {
binder::Status ret = binder::Status::ok();
@@ -1786,11 +1818,11 @@
if (dev == nullptr) {
return ret; // device has been closed
}
+
int sequenceId = resultExtras.requestId;
int64_t frameNumber = resultExtras.frameNumber;
int32_t burstId = resultExtras.burstId;
bool isPartialResult = (resultExtras.partialResultCount < dev->mPartialResultCount);
-
if (!isPartialResult) {
ALOGV("SeqId %d frame %" PRId64 " result arrive.", sequenceId, frameNumber);
}
@@ -1808,7 +1840,13 @@
return ret;
}
- CameraMetadata metadataCopy = metadata;
+ CameraMetadata metadataCopy;
+ camera_status_t status = readOneResultMetadata(resultMetadata,
+ dev->mCaptureResultMetadataQueue.get(), &metadataCopy);
+ if (status != ACAMERA_OK) {
+ ALOGE("%s: result metadata couldn't be converted", __FUNCTION__);
+ return ret;
+ }
metadataCopy.update(ANDROID_LENS_INFO_SHADING_MAP_SIZE, dev->mShadingMapSize, /*data_count*/2);
metadataCopy.update(ANDROID_SYNC_FRAME_NUMBER, &frameNumber, /*data_count*/1);
@@ -1824,8 +1862,24 @@
sp<CaptureRequest> request = cbh.mRequests[burstId];
sp<ACameraMetadata> result(new ACameraMetadata(
metadataCopy.release(), ACameraMetadata::ACM_RESULT));
+
+ std::vector<PhysicalCaptureResultInfo> localPhysicalResult;
+ localPhysicalResult.resize(physicalResultInfos.size());
+ for (size_t i = 0; i < physicalResultInfos.size(); i++) {
+ CameraMetadata physicalMetadata;
+ localPhysicalResult[i].mPhysicalCameraId = physicalResultInfos[i].mPhysicalCameraId;
+ status = readOneResultMetadata(physicalResultInfos[i].mCameraMetadataInfo,
+ dev->mCaptureResultMetadataQueue.get(),
+ &physicalMetadata);
+ if (status != ACAMERA_OK) {
+ ALOGE("%s: physical camera result metadata couldn't be converted", __FUNCTION__);
+ return ret;
+ }
+ localPhysicalResult[i].mCameraMetadataInfo.set<CameraMetadataInfo::metadata>(
+ std::move(physicalMetadata));
+ }
sp<ACameraPhysicalCaptureResultInfo> physicalResult(
- new ACameraPhysicalCaptureResultInfo(physicalResultInfos, frameNumber));
+ new ACameraPhysicalCaptureResultInfo(localPhysicalResult, frameNumber));
sp<AMessage> msg = new AMessage(
cbh.mIsLogicalCameraCallback ? kWhatLogicalCaptureResult : kWhatCaptureResult,
@@ -1946,5 +2000,28 @@
}
}
+camera_status_t CameraDevice::ServiceCallback::readOneResultMetadata(
+ const CameraMetadataInfo& resultInfo, ResultMetadataQueue* metadataQueue,
+ CameraMetadata* metadata) {
+ if (metadataQueue == nullptr || metadata == nullptr) {
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ if (resultInfo.getTag() == CameraMetadataInfo::fmqSize) {
+ int64_t metadataSize = resultInfo.get<CameraMetadataInfo::fmqSize>();
+ auto metadataVec = std::make_unique<int8_t []>(metadataSize);
+ bool read = metadataQueue->read(reinterpret_cast<int8_t*>(metadataVec.get()), metadataSize);
+ if (!read) {
+ ALOGE("%s capture request settings could't be read from fmq", __FUNCTION__);
+ return ACAMERA_ERROR_UNKNOWN;
+ }
+ *metadata = CameraMetadata(reinterpret_cast<camera_metadata_t *>(metadataVec.release()));
+ } else {
+ *metadata =
+ resultInfo.get<CameraMetadataInfo::metadata>();
+ }
+
+ return ACAMERA_OK;
+}
+
} // namespace acam
} // namespace android
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h
index d3aed4b..ea7d9b6 100644
--- a/camera/ndk/impl/ACameraDevice.h
+++ b/camera/ndk/impl/ACameraDevice.h
@@ -37,15 +37,20 @@
#include <camera/camera2/OutputConfiguration.h>
#include <camera/camera2/SessionConfiguration.h>
#include <camera/camera2/CaptureRequest.h>
+#include <fmq/AidlMessageQueueCpp.h>
-#include <camera/NdkCameraManager.h>
#include <camera/NdkCameraCaptureSession.h>
+#include <camera/NdkCameraManager.h>
+#include <gui/Flags.h> // remove with WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
#include "ACameraMetadata.h"
namespace android {
namespace acam {
+using android::hardware::common::fmq::SynchronizedReadWrite;
+using ResultMetadataQueue = AidlMessageQueueCpp<int8_t, SynchronizedReadWrite>;
+
// Wrap ACameraCaptureFailure so it can be ref-counted
struct CameraCaptureFailure : public RefBase, public ACameraCaptureFailure {};
@@ -61,6 +66,8 @@
class CameraDevice final : public RefBase {
public:
+
+ using CameraMetadataInfo = android::hardware::camera2::CameraMetadataInfo;
CameraDevice(const char* id, ACameraDevice_StateCallbacks* cb,
sp<ACameraMetadata> chars,
ACameraDevice* wrapper, bool sharedMode);
@@ -91,7 +98,7 @@
binder::Status onDeviceIdle() override;
binder::Status onCaptureStarted(const CaptureResultExtras& resultExtras,
int64_t timestamp) override;
- binder::Status onResultReceived(const CameraMetadata& metadata,
+ binder::Status onResultReceived(const CameraMetadataInfo &resultInfo,
const CaptureResultExtras& resultExtras,
const std::vector<PhysicalCaptureResultInfo>& physicalResultInfos) override;
binder::Status onPrepared(int streamId) override;
@@ -100,6 +107,9 @@
int32_t stoppedSequenceId) override;
binder::Status onClientSharedAccessPriorityChanged(bool isPrimaryClient) override;
private:
+ camera_status_t readOneResultMetadata(
+ const CameraMetadataInfo& resultInfo, ResultMetadataQueue* metadataQueue,
+ CameraMetadata* metadata);
const wp<CameraDevice> mDevice;
};
inline sp<hardware::camera2::ICameraDeviceCallbacks> getServiceCallback() {
@@ -108,6 +118,7 @@
// Camera device is only functional after remote being set
void setRemoteDevice(sp<hardware::camera2::ICameraDeviceUser> remote);
+ bool setDeviceMetadataQueues();
inline ACameraDevice* getWrapper() const { return mWrapper; };
@@ -178,8 +189,10 @@
// Input message will be posted and cleared after this returns
void postSessionMsgAndCleanup(sp<AMessage>& msg);
- static camera_status_t getIGBPfromAnw(
- ANativeWindow* anw, sp<IGraphicBufferProducer>& out);
+ // Only used when WB_LIBCAMERASERVICE_WITH_DEPENDENCIES is active
+ static ParcelableSurfaceType convertSurfaceTypeToView(sp<SurfaceType> surface);
+
+ static camera_status_t getSurfacefromAnw(ANativeWindow* anw, sp<SurfaceType>& out);
static camera_status_t getSurfaceFromANativeWindow(
ANativeWindow* anw, sp<Surface>& out);
@@ -399,6 +412,9 @@
int32_t mPartialResultCount; // const after constructor
std::vector<std::string> mPhysicalIds; // const after constructor
+ // Metadata queue to write the result metadata to.
+ std::unique_ptr<ResultMetadataQueue> mCaptureResultMetadataQueue;
+
};
} // namespace acam;
@@ -452,6 +468,10 @@
mDevice->setRemoteDevice(remote);
}
+ inline bool setDeviceMetadataQueues() {
+ return mDevice->setDeviceMetadataQueues();
+ }
+
inline void setPrimaryClient(bool isPrimary) {
mDevice->setPrimaryClient(isPrimary);
}
diff --git a/camera/ndk/impl/ACameraManager.cpp b/camera/ndk/impl/ACameraManager.cpp
index f9c1a8a..acd7917 100644
--- a/camera/ndk/impl/ACameraManager.cpp
+++ b/camera/ndk/impl/ACameraManager.cpp
@@ -971,6 +971,7 @@
return ACAMERA_ERROR_CAMERA_DISCONNECTED;
}
device->setRemoteDevice(deviceRemote);
+ device->setDeviceMetadataQueues();
if (flags::camera_multi_client() && sharedMode) {
binder::Status remoteRet = deviceRemote->isPrimaryClient(primaryClient);
if (!remoteRet.isOk()) {
diff --git a/camera/tests/CameraBinderTests.cpp b/camera/tests/CameraBinderTests.cpp
index 4384df9..5f7f2f6 100644
--- a/camera/tests/CameraBinderTests.cpp
+++ b/camera/tests/CameraBinderTests.cpp
@@ -63,6 +63,7 @@
using namespace android;
using ::android::hardware::ICameraService;
using ::android::hardware::camera2::ICameraDeviceUser;
+using ::android::hardware::camera2::CameraMetadataInfo;
#define ASSERT_NOT_NULL(x) \
ASSERT_TRUE((x) != nullptr)
@@ -249,10 +250,10 @@
return binder::Status::ok();
}
- virtual binder::Status onResultReceived(const CameraMetadata& metadata,
+ virtual binder::Status onResultReceived(const CameraMetadataInfo& resultInfo,
const CaptureResultExtras& resultExtras,
const std::vector<PhysicalCaptureResultInfo>& physicalResultInfos) {
- (void) metadata;
+ (void) resultInfo;
(void) resultExtras;
(void) physicalResultInfos;
Mutex::Autolock l(mLock);
diff --git a/camera/tests/fuzzer/camera_c2OutputConfiguration_fuzzer.cpp b/camera/tests/fuzzer/camera_c2OutputConfiguration_fuzzer.cpp
index b6fa817..22e04fc 100644
--- a/camera/tests/fuzzer/camera_c2OutputConfiguration_fuzzer.cpp
+++ b/camera/tests/fuzzer/camera_c2OutputConfiguration_fuzzer.cpp
@@ -19,6 +19,7 @@
#include <fuzzer/FuzzedDataProvider.h>
#include <gui/IGraphicBufferProducer.h>
#include <gui/Surface.h>
+#include <gui/Flags.h> // remove with WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
#include <gui/SurfaceComposerClient.h>
#include "camera2common.h"
@@ -37,11 +38,11 @@
private:
void invokeC2OutputConfigFuzzer();
unique_ptr<OutputConfiguration> getC2OutputConfig();
- sp<IGraphicBufferProducer> createIGraphicBufferProducer();
+ sp<SurfaceType> createSurface();
FuzzedDataProvider* mFDP = nullptr;
};
-sp<IGraphicBufferProducer> C2OutputConfigurationFuzzer::createIGraphicBufferProducer() {
+sp<SurfaceType> C2OutputConfigurationFuzzer::createSurface() {
sp<SurfaceComposerClient> composerClient = new SurfaceComposerClient;
sp<SurfaceControl> surfaceControl = composerClient->createSurface(
static_cast<String8>(mFDP->ConsumeRandomLengthString(kMaxBytes).c_str()) /* name */,
@@ -51,10 +52,9 @@
mFDP->ConsumeIntegral<int32_t>() /* flags */);
if (surfaceControl) {
sp<Surface> surface = surfaceControl->getSurface();
- return surface->getIGraphicBufferProducer();
+ return flagtools::surfaceToSurfaceType(surface);
} else {
- sp<IGraphicBufferProducer> gbp;
- return gbp;
+ return nullptr;
}
}
@@ -69,9 +69,9 @@
string physicalCameraId = mFDP->ConsumeRandomLengthString(kMaxBytes);
int32_t surfaceSetID = mFDP->ConsumeIntegral<int32_t>();
bool isShared = mFDP->ConsumeBool();
- sp<IGraphicBufferProducer> iGBP = createIGraphicBufferProducer();
+ sp<SurfaceType> surface = createSurface();
outputConfiguration = make_unique<OutputConfiguration>(
- iGBP, rotation, physicalCameraId, surfaceSetID, isShared);
+ surface, rotation, physicalCameraId, surfaceSetID, isShared);
},
[&]() {
@@ -79,14 +79,15 @@
string physicalCameraId = mFDP->ConsumeRandomLengthString(kMaxBytes);
int32_t surfaceSetID = mFDP->ConsumeIntegral<int32_t>();
bool isShared = mFDP->ConsumeBool();
- size_t iGBPSize = mFDP->ConsumeIntegralInRange<size_t>(kSizeMin, kSizeMax);
- vector<sp<IGraphicBufferProducer>> iGBPs;
- for (size_t idx = 0; idx < iGBPSize; ++idx) {
- sp<IGraphicBufferProducer> iGBP = createIGraphicBufferProducer();
- iGBPs.push_back(iGBP);
+ size_t surfaceSize =
+ mFDP->ConsumeIntegralInRange<size_t>(kSizeMin, kSizeMax);
+ vector<sp<SurfaceType>> surfaces;
+ for (size_t idx = 0; idx < surfaceSize; ++idx) {
+ sp<SurfaceType> surface = createSurface();
+ surfaces.push_back(surface);
}
outputConfiguration = make_unique<OutputConfiguration>(
- iGBPs, rotation, physicalCameraId, surfaceSetID, isShared);
+ surfaces, rotation, physicalCameraId, surfaceSetID, isShared);
},
});
selectOutputConfigurationConstructor();
@@ -107,22 +108,22 @@
[&]() { outputConfiguration->isDeferred(); },
[&]() { outputConfiguration->isShared(); },
[&]() { outputConfiguration->getPhysicalCameraId(); },
- [&]() { outputConfiguration->gbpsEqual(*outputConfiguration2); },
+ [&]() { outputConfiguration->surfacesEqual(*outputConfiguration2); },
[&]() { outputConfiguration->sensorPixelModesUsedEqual(*outputConfiguration2); },
- [&]() { outputConfiguration->gbpsLessThan(*outputConfiguration2); },
+ [&]() { outputConfiguration->surfacesLessThan(*outputConfiguration2); },
[&]() { outputConfiguration->sensorPixelModesUsedLessThan(*outputConfiguration2); },
- [&]() { outputConfiguration->getGraphicBufferProducers(); },
+ [&]() { outputConfiguration->getSurfaces(); },
[&]() {
- sp<IGraphicBufferProducer> gbp = createIGraphicBufferProducer();
- outputConfiguration->addGraphicProducer(gbp);
+ sp<SurfaceType> surface = createSurface();
+ outputConfiguration->addSurface(surface);
},
[&]() { outputConfiguration->isMultiResolution(); },
[&]() { outputConfiguration->getColorSpace(); },
[&]() { outputConfiguration->getStreamUseCase(); },
[&]() { outputConfiguration->getTimestampBase(); },
[&]() {
- sp<IGraphicBufferProducer> gbp = createIGraphicBufferProducer();
- outputConfiguration->getMirrorMode(gbp);
+ sp<SurfaceType> surface = createSurface();
+ outputConfiguration->getMirrorMode(surface);
},
[&]() { outputConfiguration->useReadoutTimestamp(); },
});
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index 754f066..eaa5bd5 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -288,10 +288,10 @@
}
DrmStatus DrmHal::getSupportedSchemes(std::vector<uint8_t>& schemes) const {
- status_t statusResult;
- statusResult = mDrmHalAidl->getSupportedSchemes(schemes);
- if (statusResult == OK) return statusResult;
- return mDrmHalHidl->getSupportedSchemes(schemes);
+ const DrmStatus statusResultAidl = mDrmHalAidl->getSupportedSchemes(schemes);
+ const DrmStatus statusResultHidl = mDrmHalHidl->getSupportedSchemes(schemes);
+ if (statusResultHidl == OK || statusResultAidl == OK) return OK;
+ return statusResultAidl;
}
} // namespace android
diff --git a/media/OWNERS b/media/OWNERS
index b926075..5e32047 100644
--- a/media/OWNERS
+++ b/media/OWNERS
@@ -1,6 +1,7 @@
# Bug component: 1344
elaurent@google.com
essick@google.com
+atneya@google.com
hunga@google.com
jiabin@google.com
jmtrivi@google.com
diff --git a/media/aconfig/codec_fwk.aconfig b/media/aconfig/codec_fwk.aconfig
index 96fb3e3..a1413b7 100644
--- a/media/aconfig/codec_fwk.aconfig
+++ b/media/aconfig/codec_fwk.aconfig
@@ -29,6 +29,13 @@
}
flag {
+ name: "codec_availability_support"
+ namespace: "codec_fwk"
+ description: "Feature flag for codec availability HAL API implementation"
+ bug: "363282971"
+}
+
+flag {
name: "codec_buffer_state_cleanup"
namespace: "codec_fwk"
description: "Bugfix flag for more buffer state cleanup in MediaCodec"
@@ -123,6 +130,7 @@
namespace: "codec_fwk"
description: "Feature flag for exposing number of input slots"
bug: "159891571"
+ is_exported: true
}
flag {
@@ -200,6 +208,7 @@
namespace: "codec_fwk"
description: "Feature flag for subsession codec metrics"
bug: "363382811"
+ is_exported: true
}
flag {
diff --git a/media/aconfig/mediacodec_flags.aconfig b/media/aconfig/mediacodec_flags.aconfig
index 3cc9a1a..2679920 100644
--- a/media/aconfig/mediacodec_flags.aconfig
+++ b/media/aconfig/mediacodec_flags.aconfig
@@ -26,4 +26,5 @@
namespace: "codec_fwk"
description: "Feature flags for large audio frame support"
bug: "297219557"
+ is_exported: true
}
diff --git a/media/aconfig/swcodec_flags.aconfig b/media/aconfig/swcodec_flags.aconfig
index a435a43..9dd1fdd 100644
--- a/media/aconfig/swcodec_flags.aconfig
+++ b/media/aconfig/swcodec_flags.aconfig
@@ -12,3 +12,12 @@
description: "Feature flag for APV Software C2 codec"
bug: "376770121"
}
+
+flag {
+ name: "mpeg2_keep_threads_active"
+ is_exported: true
+ is_fixed_read_only: true
+ namespace: "codec_fwk"
+ description: "Enable keep_threads_active in mpeg2 decoder"
+ bug: "343793479"
+}
diff --git a/media/audio/aconfig/audio_framework.aconfig b/media/audio/aconfig/audio_framework.aconfig
index 1450417..d157a97 100644
--- a/media/audio/aconfig/audio_framework.aconfig
+++ b/media/audio/aconfig/audio_framework.aconfig
@@ -30,6 +30,7 @@
"New privileged permission to allow bypassing concurrent audio"
"capture rules."
bug: "374751406"
+ is_exported: true
}
flag {
@@ -82,6 +83,7 @@
description: "Feature flag for Dolby AC-4 level 4 AudioFormat encoding."
is_fixed_read_only: true
bug: "266537650"
+ is_exported: true
}
# TODO remove
@@ -158,6 +160,7 @@
namespace: "media_audio"
description: "Playback monitoring flag used when player muted by port volume"
bug: "319515324"
+ is_exported: true
}
flag {
@@ -204,6 +207,7 @@
"Enable Java and native functions to get"
"multiple routed device ids"
bug: "367816690"
+ is_exported: true
}
flag {
@@ -218,6 +222,7 @@
namespace: "media_audio"
description: "spatializer reports effective channel masks"
bug: "377582613"
+ is_exported: true
}
flag {
@@ -225,6 +230,7 @@
namespace: "media_audio"
description: "Support new AudioAttributes usage for speaker cleanup"
bug: "355050846"
+ is_exported: true
}
flag {
@@ -232,6 +238,7 @@
namespace: "media_audio"
description: "Surface new API method for returning speaker layout channel mask for devices"
bug: "337522902"
+ is_exported: true
}
# TODO remove
diff --git a/media/audioaidlconversion/AidlConversionCppNdk.cpp b/media/audioaidlconversion/AidlConversionCppNdk.cpp
index 95a8a69..f739f3c 100644
--- a/media/audioaidlconversion/AidlConversionCppNdk.cpp
+++ b/media/audioaidlconversion/AidlConversionCppNdk.cpp
@@ -76,8 +76,6 @@
using media::audio::common::AudioOffloadInfo;
using media::audio::common::AudioOutputFlags;
using media::audio::common::AudioPlaybackRate;
-using media::audio::common::AudioPolicyForcedConfig;
-using media::audio::common::AudioPolicyForceUse;
using media::audio::common::AudioPort;
using media::audio::common::AudioPortConfig;
using media::audio::common::AudioPortDeviceExt;
@@ -3359,138 +3357,6 @@
return OK;
}
-ConversionResult<audio_policy_force_use_t>
-aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t(AudioPolicyForceUse aidl) {
- switch (aidl) {
- case AudioPolicyForceUse::COMMUNICATION:
- return AUDIO_POLICY_FORCE_FOR_COMMUNICATION;
- case AudioPolicyForceUse::MEDIA:
- return AUDIO_POLICY_FORCE_FOR_MEDIA;
- case AudioPolicyForceUse::RECORD:
- return AUDIO_POLICY_FORCE_FOR_RECORD;
- case AudioPolicyForceUse::DOCK:
- return AUDIO_POLICY_FORCE_FOR_DOCK;
- case AudioPolicyForceUse::SYSTEM:
- return AUDIO_POLICY_FORCE_FOR_SYSTEM;
- case AudioPolicyForceUse::HDMI_SYSTEM_AUDIO:
- return AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO;
- case AudioPolicyForceUse::ENCODED_SURROUND:
- return AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND;
- case AudioPolicyForceUse::VIBRATE_RINGING:
- return AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING;
- }
- return unexpected(BAD_VALUE);
-}
-
-ConversionResult<AudioPolicyForceUse>
-legacy2aidl_audio_policy_force_use_t_AudioPolicyForceUse(audio_policy_force_use_t legacy) {
- switch (legacy) {
- case AUDIO_POLICY_FORCE_FOR_COMMUNICATION:
- return AudioPolicyForceUse::COMMUNICATION;
- case AUDIO_POLICY_FORCE_FOR_MEDIA:
- return AudioPolicyForceUse::MEDIA;
- case AUDIO_POLICY_FORCE_FOR_RECORD:
- return AudioPolicyForceUse::RECORD;
- case AUDIO_POLICY_FORCE_FOR_DOCK:
- return AudioPolicyForceUse::DOCK;
- case AUDIO_POLICY_FORCE_FOR_SYSTEM:
- return AudioPolicyForceUse::SYSTEM;
- case AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO:
- return AudioPolicyForceUse::HDMI_SYSTEM_AUDIO;
- case AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND:
- return AudioPolicyForceUse::ENCODED_SURROUND;
- case AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING:
- return AudioPolicyForceUse::VIBRATE_RINGING;
- case AUDIO_POLICY_FORCE_USE_CNT:
- break;
- }
- return unexpected(BAD_VALUE);
-}
-
-ConversionResult<audio_policy_forced_cfg_t>
-aidl2legacy_AudioPolicyForcedConfig_audio_policy_forced_cfg_t(AudioPolicyForcedConfig aidl) {
- switch (aidl) {
- case AudioPolicyForcedConfig::NONE:
- return AUDIO_POLICY_FORCE_NONE;
- case AudioPolicyForcedConfig::SPEAKER:
- return AUDIO_POLICY_FORCE_SPEAKER;
- case AudioPolicyForcedConfig::HEADPHONES:
- return AUDIO_POLICY_FORCE_HEADPHONES;
- case AudioPolicyForcedConfig::BT_SCO:
- return AUDIO_POLICY_FORCE_BT_SCO;
- case AudioPolicyForcedConfig::BT_A2DP:
- return AUDIO_POLICY_FORCE_BT_A2DP;
- case AudioPolicyForcedConfig::WIRED_ACCESSORY:
- return AUDIO_POLICY_FORCE_WIRED_ACCESSORY;
- case AudioPolicyForcedConfig::BT_CAR_DOCK:
- return AUDIO_POLICY_FORCE_BT_CAR_DOCK;
- case AudioPolicyForcedConfig::BT_DESK_DOCK:
- return AUDIO_POLICY_FORCE_BT_DESK_DOCK;
- case AudioPolicyForcedConfig::ANALOG_DOCK:
- return AUDIO_POLICY_FORCE_ANALOG_DOCK;
- case AudioPolicyForcedConfig::DIGITAL_DOCK:
- return AUDIO_POLICY_FORCE_DIGITAL_DOCK;
- case AudioPolicyForcedConfig::NO_BT_A2DP:
- return AUDIO_POLICY_FORCE_NO_BT_A2DP;
- case AudioPolicyForcedConfig::SYSTEM_ENFORCED:
- return AUDIO_POLICY_FORCE_SYSTEM_ENFORCED;
- case AudioPolicyForcedConfig::HDMI_SYSTEM_AUDIO_ENFORCED:
- return AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED;
- case AudioPolicyForcedConfig::ENCODED_SURROUND_NEVER:
- return AUDIO_POLICY_FORCE_ENCODED_SURROUND_NEVER;
- case AudioPolicyForcedConfig::ENCODED_SURROUND_ALWAYS:
- return AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS;
- case AudioPolicyForcedConfig::ENCODED_SURROUND_MANUAL:
- return AUDIO_POLICY_FORCE_ENCODED_SURROUND_MANUAL;
- case AudioPolicyForcedConfig::BT_BLE:
- return AUDIO_POLICY_FORCE_BT_BLE;
- }
- return unexpected(BAD_VALUE);
-}
-
-ConversionResult<AudioPolicyForcedConfig>
-legacy2aidl_audio_policy_forced_cfg_t_AudioPolicyForcedConfig(audio_policy_forced_cfg_t legacy) {
- switch (legacy) {
- case AUDIO_POLICY_FORCE_NONE:
- return AudioPolicyForcedConfig::NONE;
- case AUDIO_POLICY_FORCE_SPEAKER:
- return AudioPolicyForcedConfig::SPEAKER;
- case AUDIO_POLICY_FORCE_HEADPHONES:
- return AudioPolicyForcedConfig::HEADPHONES;
- case AUDIO_POLICY_FORCE_BT_SCO:
- return AudioPolicyForcedConfig::BT_SCO;
- case AUDIO_POLICY_FORCE_BT_A2DP:
- return AudioPolicyForcedConfig::BT_A2DP;
- case AUDIO_POLICY_FORCE_WIRED_ACCESSORY:
- return AudioPolicyForcedConfig::WIRED_ACCESSORY;
- case AUDIO_POLICY_FORCE_BT_CAR_DOCK:
- return AudioPolicyForcedConfig::BT_CAR_DOCK;
- case AUDIO_POLICY_FORCE_BT_DESK_DOCK:
- return AudioPolicyForcedConfig::BT_DESK_DOCK;
- case AUDIO_POLICY_FORCE_ANALOG_DOCK:
- return AudioPolicyForcedConfig::ANALOG_DOCK;
- case AUDIO_POLICY_FORCE_DIGITAL_DOCK:
- return AudioPolicyForcedConfig::DIGITAL_DOCK;
- case AUDIO_POLICY_FORCE_NO_BT_A2DP:
- return AudioPolicyForcedConfig::NO_BT_A2DP;
- case AUDIO_POLICY_FORCE_SYSTEM_ENFORCED:
- return AudioPolicyForcedConfig::SYSTEM_ENFORCED;
- case AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED:
- return AudioPolicyForcedConfig::HDMI_SYSTEM_AUDIO_ENFORCED;
- case AUDIO_POLICY_FORCE_ENCODED_SURROUND_NEVER:
- return AudioPolicyForcedConfig::ENCODED_SURROUND_NEVER;
- case AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS:
- return AudioPolicyForcedConfig::ENCODED_SURROUND_ALWAYS;
- case AUDIO_POLICY_FORCE_ENCODED_SURROUND_MANUAL:
- return AudioPolicyForcedConfig::ENCODED_SURROUND_MANUAL;
- case AUDIO_POLICY_FORCE_BT_BLE:
- return AudioPolicyForcedConfig::BT_BLE;
- case AUDIO_POLICY_FORCE_CFG_CNT:
- break;
- }
- return unexpected(BAD_VALUE);
-}
-
} // namespace android
#undef GET_DEVICE_DESC_CONNECTION
diff --git a/media/audioaidlconversion/include/media/AidlConversionCppNdk-impl.h b/media/audioaidlconversion/include/media/AidlConversionCppNdk-impl.h
index 9dfb7e7..7268464 100644
--- a/media/audioaidlconversion/include/media/AidlConversionCppNdk-impl.h
+++ b/media/audioaidlconversion/include/media/AidlConversionCppNdk-impl.h
@@ -58,8 +58,6 @@
#include PREFIX(android/media/audio/common/AudioMode.h)
#include PREFIX(android/media/audio/common/AudioOffloadInfo.h)
#include PREFIX(android/media/audio/common/AudioOutputFlags.h)
-#include PREFIX(android/media/audio/common/AudioPolicyForceUse.h)
-#include PREFIX(android/media/audio/common/AudioPolicyForcedConfig.h)
#include PREFIX(android/media/audio/common/AudioPort.h)
#include PREFIX(android/media/audio/common/AudioPortConfig.h)
#include PREFIX(android/media/audio/common/AudioPortExt.h)
@@ -78,7 +76,6 @@
#include <system/audio.h>
#include <system/audio_effect.h>
-#include <system/audio_policy.h>
#if defined(BACKEND_NDK_IMPL)
namespace aidl {
@@ -457,18 +454,6 @@
media::audio::common::MicrophoneInfo* aidlInfo,
media::audio::common::MicrophoneDynamicInfo* aidlDynamic);
-ConversionResult<audio_policy_forced_cfg_t>
-aidl2legacy_AudioPolicyForcedConfig_audio_policy_forced_cfg_t(
- media::audio::common::AudioPolicyForcedConfig aidl);
-ConversionResult<media::audio::common::AudioPolicyForcedConfig>
-legacy2aidl_audio_policy_forced_cfg_t_AudioPolicyForcedConfig(audio_policy_forced_cfg_t legacy);
-
-ConversionResult<audio_policy_force_use_t>
-aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t(
- media::audio::common::AudioPolicyForceUse aidl);
-ConversionResult<media::audio::common::AudioPolicyForceUse>
-legacy2aidl_audio_policy_force_use_t_AudioPolicyForceUse(audio_policy_force_use_t legacy);
-
} // namespace android
#if defined(BACKEND_NDK_IMPL)
diff --git a/media/codec2/components/apv/C2SoftApvEnc.cpp b/media/codec2/components/apv/C2SoftApvEnc.cpp
index d6a9597..9c5e0b2 100644
--- a/media/codec2/components/apv/C2SoftApvEnc.cpp
+++ b/media/codec2/components/apv/C2SoftApvEnc.cpp
@@ -958,108 +958,98 @@
finish(workIndex, fillWork);
}
}
-void C2SoftApvEnc::createCsdData(const std::unique_ptr<C2Work>& work, oapv_bitb_t* bitb,
- uint32_t encodedSize) {
- uint32_t csdStart = 0, csdEnd = 0;
- uint32_t bitOffset = 0;
- uint8_t* buf = (uint8_t*)bitb->addr + csdStart;
- if (encodedSize == 0) {
- ALOGE("the first frame size is zero, so no csd data will be created.");
+void C2SoftApvEnc::createCsdData(const std::unique_ptr<C2Work>& work,
+ oapv_bitb_t* bitb,
+ uint32_t encodedSize) {
+ if (encodedSize < 31) {
+ ALOGE("the first frame size is too small, so no csd data will be created.");
return;
}
- ABitReader reader(buf, encodedSize);
+ ABitReader reader((uint8_t*)bitb->addr, encodedSize);
+
+ uint8_t number_of_configuration_entry = 0;
+ uint8_t pbu_type = 0;
+ uint8_t number_of_frame_info = 0;
+ bool color_description_present_flag = false;
+ bool capture_time_distance_ignored = false;
+ uint8_t profile_idc = 0;
+ uint8_t level_idc = 0;
+ uint8_t band_idc = 0;
+ uint32_t frame_width_minus1 = 0;
+ uint32_t frame_height_minus1 = 0;
+ uint8_t chroma_format_idc = 0;
+ uint8_t bit_depth_minus8 = 0;
+ uint8_t capture_time_distance = 0;
+ uint8_t color_primaries = 0;
+ uint8_t transfer_characteristics = 0;
+ uint8_t matrix_coefficients = 0;
/* pbu_header() */
- reader.skipBits(32);
- bitOffset += 32; // pbu_size
- reader.skipBits(32);
- bitOffset += 32; // currReadSize
- csdStart = bitOffset / 8;
-
- int32_t pbu_type = reader.getBits(8);
- bitOffset += 8; // pbu_type
- reader.skipBits(16);
- bitOffset += 16; // group_id
- reader.skipBits(8);
- bitOffset += 8; // reserved_zero_8bits
+ reader.skipBits(32); // pbu_size
+ reader.skipBits(32); // currReadSize
+ pbu_type = reader.getBits(8); // pbu_type
+ reader.skipBits(16); // group_id
+ reader.skipBits(8); // reserved_zero_8bits
/* frame info() */
- int32_t profile_idc = reader.getBits(8);
- bitOffset += 8; // profile_idc
- int32_t level_idc = reader.getBits(8);
- bitOffset += 8; // level_idc
- int32_t band_idc = reader.getBits(3);
- bitOffset += 3; // band_idc
- reader.skipBits(5);
- bitOffset += 5; // reserved_zero_5bits
- int32_t width = reader.getBits(32);
- bitOffset += 32; // width
- int32_t height = reader.getBits(32);
- bitOffset += 32; // height
- int32_t chroma_idc = reader.getBits(4);
- bitOffset += 4; // chroma_format_idc
- reader.skipBits(4);
- bitOffset += 4; // bit_depth
- reader.skipBits(8);
- bitOffset += 8; // capture_time_distance
- reader.skipBits(8);
- bitOffset += 8; // reserved_zero_8bits
+ profile_idc = reader.getBits(8); // profile_idc
+ level_idc = reader.getBits(8); // level_idc
+ band_idc = reader.getBits(3); // band_idc
+ reader.skipBits(5); // reserved_zero_5bits
+ frame_width_minus1 = reader.getBits(32); // width
+ frame_height_minus1 = reader.getBits(32); // height
+ chroma_format_idc = reader.getBits(4); // chroma_format_idc
+ bit_depth_minus8 = reader.getBits(4); // bit_depth
+ capture_time_distance = reader.getBits(8); // capture_time_distance
+ reader.skipBits(8); // reserved_zero_8bits
/* frame header() */
- reader.skipBits(8);
- bitOffset += 8; // reserved_zero_8bit
- bool color_description_present_flag = reader.getBits(1);
- bitOffset += 1; // color_description_present_flag
+ reader.skipBits(8); // reserved_zero_8bit
+ color_description_present_flag = reader.getBits(1); // color_description_present_flag
if (color_description_present_flag) {
- reader.skipBits(8);
- bitOffset += 8; // color_primaries
- reader.skipBits(8);
- bitOffset += 8; // transfer_characteristics
- reader.skipBits(8);
- bitOffset += 8; // matrix_coefficients
- }
- bool use_q_matrix = reader.getBits(1);
- bitOffset += 1; // use_q_matrix
- if (use_q_matrix) {
- /* quantization_matrix() */
- int32_t numComp = chroma_idc == 0 ? 1
- : chroma_idc == 2 ? 3
- : chroma_idc == 3 ? 3
- : chroma_idc == 4 ? 4
- : -1;
- int32_t needBitsForQ = 64 * 8 * numComp;
- reader.skipBits(needBitsForQ);
- bitOffset += needBitsForQ;
+ color_primaries = reader.getBits(8); // color_primaries
+ transfer_characteristics = reader.getBits(8); // transfer_characteristics
+ matrix_coefficients = reader.getBits(8); // matrix_coefficients
}
- /* tile_info() */
- int32_t tile_width_in_mbs_minus1 = reader.getBits(28);
- bitOffset += 28;
- int32_t tile_height_in_mbs_minus1 = reader.getBits(28);
- bitOffset += 28;
- bool tile_size_present_in_fh_flag = reader.getBits(1);
- bitOffset += 1;
- if (tile_size_present_in_fh_flag) {
- int32_t numTiles = ceil((double)width / (double)tile_width_in_mbs_minus1) *
- ceil((double)height / (double)tile_height_in_mbs_minus1);
- reader.skipBits(32 * numTiles);
- bitOffset += (32 * numTiles);
- }
+ number_of_configuration_entry = 1; // The real-time encoding on the device is assumed to be 1.
+ number_of_frame_info = 1; // The real-time encoding on the device is assumed to be 1.
- reader.skipBits(8);
- bitOffset += 8; // reserved_zero_8bits
+ std::vector<uint8_t> csdData;
+ csdData.push_back((uint8_t)0x1);
+ csdData.push_back(number_of_configuration_entry);
- /* byte_alignmenet() */
- while (bitOffset % 8) {
- reader.skipBits(1);
- bitOffset += 1;
+ for (uint8_t i = 0; i < number_of_configuration_entry; i++) {
+ csdData.push_back(pbu_type);
+ csdData.push_back(number_of_frame_info);
+ for (uint8_t j = 0; j < number_of_frame_info; j++) {
+ csdData.push_back((uint8_t)((color_description_present_flag << 1) |
+ capture_time_distance_ignored));
+ csdData.push_back(profile_idc);
+ csdData.push_back(level_idc);
+ csdData.push_back(band_idc);
+ csdData.push_back((uint8_t)((frame_width_minus1 >> 24) & 0xff));
+ csdData.push_back((uint8_t)((frame_width_minus1 >> 16) & 0xff));
+ csdData.push_back((uint8_t)((frame_width_minus1 >> 8) & 0xff));
+ csdData.push_back((uint8_t)(frame_width_minus1 & 0xff));
+ csdData.push_back((uint8_t)((frame_height_minus1 >> 24) & 0xff));
+ csdData.push_back((uint8_t)((frame_height_minus1 >> 16) & 0xff));
+ csdData.push_back((uint8_t)((frame_height_minus1 >> 8) & 0xff));
+ csdData.push_back((uint8_t)(frame_height_minus1 & 0xff));
+ csdData.push_back((uint8_t)(((chroma_format_idc << 4) & 0xf0) |
+ (bit_depth_minus8 & 0xf)));
+ csdData.push_back((uint8_t)(capture_time_distance));
+ if (color_description_present_flag) {
+ csdData.push_back(color_primaries);
+ csdData.push_back(transfer_characteristics);
+ csdData.push_back(matrix_coefficients);
+ }
+ }
}
- csdEnd = bitOffset / 8;
- int32_t csdSize = csdEnd - csdStart + 1;
std::unique_ptr<C2StreamInitDataInfo::output> csd =
- C2StreamInitDataInfo::output::AllocUnique(csdSize, 0u);
+ C2StreamInitDataInfo::output::AllocUnique(csdData.size(), 0u);
if (!csd) {
ALOGE("CSD allocation failed");
mSignalledError = true;
@@ -1068,10 +1058,10 @@
return;
}
- buf = buf + csdStart;
- memcpy(csd->m.value, buf, csdSize);
+ memcpy(csd->m.value, csdData.data(), csdData.size());
work->worklets.front()->output.configUpdate.push_back(std::move(csd));
}
+
c2_status_t C2SoftApvEnc::drainInternal(uint32_t drainMode,
const std::shared_ptr<C2BlockPool>& pool,
const std::unique_ptr<C2Work>& work) {
diff --git a/media/codec2/components/mpeg2/Android.bp b/media/codec2/components/mpeg2/Android.bp
index e644ee3..ed711ee 100644
--- a/media/codec2/components/mpeg2/Android.bp
+++ b/media/codec2/components/mpeg2/Android.bp
@@ -14,11 +14,10 @@
"libcodec2_soft_sanitize_signed-defaults",
],
- cflags: [
- "-DKEEP_THREADS_ACTIVE=0",
- ],
-
srcs: ["C2SoftMpeg2Dec.cpp"],
- static_libs: ["libmpeg2dec"],
+ static_libs: [
+ "libmpeg2dec",
+ "android.media.swcodec.flags-aconfig-cc",
+ ],
}
diff --git a/media/codec2/components/mpeg2/C2SoftMpeg2Dec.cpp b/media/codec2/components/mpeg2/C2SoftMpeg2Dec.cpp
index 52920c2..64e4bf0 100644
--- a/media/codec2/components/mpeg2/C2SoftMpeg2Dec.cpp
+++ b/media/codec2/components/mpeg2/C2SoftMpeg2Dec.cpp
@@ -16,11 +16,10 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "C2SoftMpeg2Dec"
-#ifndef KEEP_THREADS_ACTIVE
-#define KEEP_THREADS_ACTIVE 0
-#endif
#include <log/log.h>
+#include <android_media_swcodec_flags.h>
+
#include <media/stagefright/foundation/MediaDefs.h>
#include <C2Debug.h>
@@ -320,14 +319,7 @@
c2_node_id_t id,
const std::shared_ptr<IntfImpl> &intfImpl)
: SimpleC2Component(std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
- mIntf(intfImpl),
- mDecHandle(nullptr),
- mMemRecords(nullptr),
- mOutBufferDrain(nullptr),
- mIvColorformat(IV_YUV_420P),
- mWidth(320),
- mHeight(240),
- mOutIndex(0u) {
+ mIntf(intfImpl) {
// If input dump is enabled, then open create an empty file
GENERATE_FILE_NAMES();
CREATE_DUMP_FILE(mInFile);
@@ -436,7 +428,7 @@
s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_size = sizeof(ivdext_fill_mem_rec_ip_t);
s_fill_mem_ip.u4_share_disp_buf = 0;
- s_fill_mem_ip.u4_keep_threads_active = KEEP_THREADS_ACTIVE;
+ s_fill_mem_ip.u4_keep_threads_active = mKeepThreadsActive;
s_fill_mem_ip.e_output_format = mIvColorformat;
s_fill_mem_ip.u4_deinterlace = 1;
s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.e_cmd = IV_CMD_FILL_NUM_MEM_REC;
@@ -478,7 +470,7 @@
s_init_ip.s_ivd_init_ip_t.u4_frm_max_ht = mHeight;
s_init_ip.u4_share_disp_buf = 0;
s_init_ip.u4_deinterlace = 1;
- s_init_ip.u4_keep_threads_active = KEEP_THREADS_ACTIVE;
+ s_init_ip.u4_keep_threads_active = mKeepThreadsActive;
s_init_ip.s_ivd_init_ip_t.u4_num_mem_rec = mNumMemRecords;
s_init_ip.s_ivd_init_ip_t.e_output_format = mIvColorformat;
s_init_op.s_ivd_init_op_t.u4_size = sizeof(ivdext_init_op_t);
@@ -571,6 +563,7 @@
status_t ret = getNumMemRecords();
if (OK != ret) return ret;
+ mKeepThreadsActive = android::media::swcodec::flags::mpeg2_keep_threads_active();
ret = fillMemRecords();
if (OK != ret) return ret;
diff --git a/media/codec2/components/mpeg2/C2SoftMpeg2Dec.h b/media/codec2/components/mpeg2/C2SoftMpeg2Dec.h
index 3965bcc..6d09694 100644
--- a/media/codec2/components/mpeg2/C2SoftMpeg2Dec.h
+++ b/media/codec2/components/mpeg2/C2SoftMpeg2Dec.h
@@ -144,21 +144,22 @@
};
std::shared_ptr<IntfImpl> mIntf;
- iv_obj_t *mDecHandle;
- iv_mem_rec_t *mMemRecords;
- size_t mNumMemRecords;
+ iv_obj_t *mDecHandle = nullptr;
+ iv_mem_rec_t *mMemRecords = nullptr;
+ size_t mNumMemRecords = 0;
std::shared_ptr<C2GraphicBlock> mOutBlock;
- uint8_t *mOutBufferDrain;
+ uint8_t *mOutBufferDrain = nullptr;
- size_t mNumCores;
- IV_COLOR_FORMAT_T mIvColorformat;
+ size_t mNumCores = 1;
+ IV_COLOR_FORMAT_T mIvColorformat = IV_YUV_420P;
- uint32_t mWidth;
- uint32_t mHeight;
- uint32_t mStride;
- bool mSignalledOutputEos;
- bool mSignalledError;
- std::atomic_uint64_t mOutIndex;
+ uint32_t mWidth = 320;
+ uint32_t mHeight = 240;
+ uint32_t mStride = 0;
+ bool mSignalledOutputEos = false;
+ bool mSignalledError = false;
+ bool mKeepThreadsActive = false;
+ std::atomic_uint64_t mOutIndex = 0;
// Color aspects. These are ISO values and are meant to detect changes in aspects to avoid
// converting them to C2 values for each frame
diff --git a/media/codec2/core/include/C2Config.h b/media/codec2/core/include/C2Config.h
index 069d6ad..fa5ce77 100644
--- a/media/codec2/core/include/C2Config.h
+++ b/media/codec2/core/include/C2Config.h
@@ -70,6 +70,7 @@
enum platform_level_t : uint32_t; ///< platform level
enum prepend_header_mode_t : uint32_t; ///< prepend header operational modes
enum profile_t : uint32_t; ///< coding profile
+ enum resource_kind_t : uint32_t; ///< resource kinds
enum scaling_method_t : uint32_t; ///< scaling methods
enum scan_order_t : uint32_t; ///< scan orders
enum secure_mode_t : uint32_t; ///< secure/protected modes
@@ -101,6 +102,7 @@
kParamIndexMasteringDisplayColorVolume,
kParamIndexChromaOffset,
kParamIndexGopLayer,
+ kParamIndexSystemResource,
/* =================================== parameter indices =================================== */
@@ -167,6 +169,10 @@
/* Region of Interest Encoding parameters */
kParamIndexQpOffsetMapBuffer, // info-buffer, used to signal qp-offset map for a frame
+ /* resource capacity and resources excluded */
+ kParamIndexResourcesCapacity,
+ kParamIndexResourcesExcluded,
+
// deprecated
kParamIndexDelayRequest = kParamIndexDelay | C2Param::CoreIndex::IS_REQUEST_FLAG,
@@ -1257,21 +1263,114 @@
/* ----------------------------------------- resources ----------------------------------------- */
/**
- * Resources needed and resources reserved for current configuration.
- *
- * Resources are tracked as a vector of positive numbers. Available resources are defined by
- * the vendor.
- *
- * By default, no resources are reserved for a component. If resource reservation is successful,
- * the component shall be able to use those resources exclusively. If however, the component is
- * not using all of the reserved resources, those may be shared with other components.
- *
- * TODO: define some of the resources.
+ * Resource kind.
*/
-typedef C2GlobalParam<C2Tuning, C2Uint64Array, kParamIndexResourcesNeeded> C2ResourcesNeededTuning;
-typedef C2GlobalParam<C2Tuning, C2Uint64Array, kParamIndexResourcesReserved>
- C2ResourcesReservedTuning;
+C2ENUM(C2Config::resource_kind_t, uint32_t,
+ CONST,
+ PER_FRAME,
+ PER_INPUT_BLOCK,
+ PER_OUTPUT_BLOCK
+)
+
+/**
+ * Definition of a system resource use.
+ *
+ * [PROPOSED]
+ *
+ * System resources are defined by the default component store.
+ * They represent any physical or abstract entities of limited availability
+ * that is required for a component instance to execute and process work.
+ *
+ * Each defined resource has an id.
+ * The use of a resource is specified by the amount and the kind (e.g. whether the amount
+ * of resources is required for each frame processed, or whether they are required
+ * regardless of the processing rate (const amount)).
+ *
+ * Note: implementations can shadow this structure with their own custom resource
+ * structure where a uint32_t based enum is used for id.
+ * This can be used to provide a name for each resource, via parameter descriptors.
+ */
+
+struct C2SystemResourceStruct {
+ C2SystemResourceStruct(uint32_t id_,
+ C2Config::resource_kind_t kind_,
+ uint64_t amount_)
+ : id(id_), kind(kind_), amount(amount_) { }
+ uint32_t id;
+ C2Config::resource_kind_t kind;
+ uint64_t amount;
+
+ DEFINE_AND_DESCRIBE_C2STRUCT(SystemResource)
+ C2FIELD(id, "id")
+ C2FIELD(kind, "kind")
+ C2FIELD(amount, "amount")
+};
+
+/**
+ * Total system resource capacity.
+ *
+ * [PROPOSED]
+ *
+ * This setting is implemented by the default component store.
+ * The total resource capacity is specified as the maximum amount for each resource ID
+ * that is supported by the device hardware or firmware.
+ * As such, the kind must be CONST for each element.
+ */
+typedef C2GlobalParam<C2Tuning,
+ C2SimpleArrayStruct<C2SystemResourceStruct>,
+ kParamIndexResourcesCapacity> C2ResourcesCapacityTuning;
+constexpr char C2_PARAMKEY_RESOURCES_CAPACITY[] = "resources.capacity";
+
+/**
+ * Excluded system resources.
+ *
+ * [PROPOSED]
+ *
+ * This setting is implemented by the default component store.
+ * Some system resources may be used by components and not tracked by the Codec 2.0 API.
+ * This is communicated by this tuning.
+ * Excluded resources are the total resources that are used by non-Codec 2.0 components.
+ * It is specified as the excluded amount for each resource ID that is used by
+ * a non-Codec 2.0 component. As such, the kind must be CONST for each element.
+ *
+ * The platform can calculate the available resources as total capacity minus
+ * excluded resource minus sum of needed resources for each component.
+ */
+typedef C2GlobalParam<C2Tuning,
+ C2SimpleArrayStruct<C2SystemResourceStruct>,
+ kParamIndexResourcesExcluded> C2ResourcesExcludedTuning;
+constexpr char C2_PARAMKEY_RESOURCES_EXCLUDED[] = "resources.excluded";
+
+/**
+ * System resources needed for the current configuration.
+ *
+ * [PROPOSED]
+ *
+ * Resources are tracked as a list of individual resource use specifications.
+ * The resource kind can be CONST, PER_FRAME, PER_INPUT_BLODCK or PER_OUTPUT_BLOCK.
+ */
+typedef C2GlobalParam<C2Tuning,
+ C2SimpleArrayStruct<C2SystemResourceStruct>,
+ kParamIndexResourcesNeeded> C2ResourcesNeededTuning;
constexpr char C2_PARAMKEY_RESOURCES_NEEDED[] = "resources.needed";
+
+/**
+ * System resources reserved for this component
+ *
+ * [FUTURE]
+ *
+ * This allows the platform to set aside system resources for the component.
+ * Since this is a static resource reservation, kind must be CONST for each element.
+ * This resource reservation only considers CONST and PER_FRAME use.
+ *
+ * By default, no resources are reserved for a component.
+ * If resource reservation is successful, the component shall be able to use those
+ * resources exclusively. If however, the component is not using all of the
+ * reserved resources, those may be shared with other components.
+ */
+typedef C2GlobalParam<C2Tuning,
+ C2SimpleArrayStruct<C2SystemResourceStruct>,
+ kParamIndexResourcesReserved> C2ResourcesReservedTuning;
constexpr char C2_PARAMKEY_RESOURCES_RESERVED[] = "resources.reserved";
/**
diff --git a/media/codec2/hal/client/Android.bp b/media/codec2/hal/client/Android.bp
index 864eeb8..029044f 100644
--- a/media/codec2/hal/client/Android.bp
+++ b/media/codec2/hal/client/Android.bp
@@ -23,6 +23,7 @@
name: "libcodec2_client",
srcs: [
+ "ApexCodecsLazy.cpp",
"GraphicBufferAllocator.cpp",
"GraphicsTracker.cpp",
"client.cpp",
@@ -41,17 +42,18 @@
cpp_std: "gnu++20",
header_libs: [
+ "libapexcodecs-header",
"libcodec2_internal", // private
],
shared_libs: [
"android.hardware.graphics.bufferqueue@1.0",
+ "android.hardware.media.bufferpool2-V2-ndk",
"android.hardware.media.bufferpool@2.0",
+ "android.hardware.media.c2-V1-ndk",
"android.hardware.media.c2@1.0",
"android.hardware.media.c2@1.1",
"android.hardware.media.c2@1.2",
- "android.hardware.media.bufferpool2-V2-ndk",
- "android.hardware.media.c2-V1-ndk",
"libbase",
"libbinder",
"libbinder_ndk",
@@ -79,6 +81,10 @@
"include",
],
+ export_header_lib_headers: [
+ "libapexcodecs-header",
+ ],
+
export_shared_lib_headers: [
"android.hardware.media.c2@1.0",
"android.hardware.media.c2@1.1",
@@ -89,5 +95,4 @@
"libcodec2_hidl_client@1.2",
"libcodec2_vndk",
],
-
}
diff --git a/media/codec2/hal/client/ApexCodecsLazy.cpp b/media/codec2/hal/client/ApexCodecsLazy.cpp
new file mode 100644
index 0000000..cd7953e
--- /dev/null
+++ b/media/codec2/hal/client/ApexCodecsLazy.cpp
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ApexCodecsLazy"
+#include <log/log.h>
+
+#include <mutex>
+
+#include <dlfcn.h>
+
+#include <android-base/no_destructor.h>
+#include <apex/ApexCodecs.h>
+#include <utils/RWLock.h>
+
+using android::RWLock;
+
+namespace {
+
+// This file provides a lazy interface to libapexcodecs.so to address early boot dependencies.
+
+// Method pointers to libapexcodecs methods are held in an array which simplifies checking
+// all pointers are initialized.
+enum MethodIndex {
+ k_ApexCodec_Component_create,
+ k_ApexCodec_Component_destroy,
+ k_ApexCodec_Component_flush,
+ k_ApexCodec_Component_getConfigurable,
+ k_ApexCodec_Component_process,
+ k_ApexCodec_Component_start,
+ k_ApexCodec_Component_reset,
+ k_ApexCodec_Configurable_config,
+ k_ApexCodec_Configurable_query,
+ k_ApexCodec_Configurable_querySupportedParams,
+ k_ApexCodec_Configurable_querySupportedValues,
+ k_ApexCodec_GetComponentStore,
+ k_ApexCodec_ParamDescriptors_getDescriptor,
+ k_ApexCodec_ParamDescriptors_getIndices,
+ k_ApexCodec_ParamDescriptors_release,
+ k_ApexCodec_SettingResults_getResultAtIndex,
+ k_ApexCodec_SettingResults_release,
+ k_ApexCodec_SupportedValues_getTypeAndValues,
+ k_ApexCodec_SupportedValues_release,
+ k_ApexCodec_Traits_get,
+
+ // Marker for count of methods
+ k_MethodCount
+};
+
+class ApexCodecsLazyLoader {
+public:
+ ApexCodecsLazyLoader() = default;
+
+ static ApexCodecsLazyLoader &Get() {
+ static ::android::base::NoDestructor<ApexCodecsLazyLoader> sLoader;
+ return *sLoader;
+ }
+
+ void *getMethodAt(enum MethodIndex index) {
+ RWLock::AutoRLock l(mLock);
+ if (mInit) {
+ return mMethods[index];
+ } else {
+ mLock.unlock();
+ if (!init()) {
+ return nullptr;
+ }
+ mLock.readLock();
+ return mMethods[index];
+ }
+ }
+
+private:
+ static void* LoadLibapexcodecs(int dlopen_flags) {
+ return dlopen("libapexcodecs.so", dlopen_flags);
+ }
+
+ // Initialization and symbol binding.
+ void bindSymbol_l(void* handle, const char* name, enum MethodIndex index) {
+ void* symbol = dlsym(handle, name);
+ ALOGI_IF(symbol == nullptr, "Failed to find symbol '%s' in libapexcodecs.so: %s",
+ name, dlerror());
+ mMethods[index] = symbol;
+ }
+
+ bool init() {
+ {
+ RWLock::AutoRLock l(mLock);
+ if (mInit) {
+ return true;
+ }
+ }
+ void* handle = LoadLibapexcodecs(RTLD_NOW);
+ if (handle == nullptr) {
+ ALOGI("Failed to load libapexcodecs.so: %s", dlerror());
+ return false;
+ }
+
+ RWLock::AutoWLock l(mLock);
+#undef BIND_SYMBOL
+#define BIND_SYMBOL(name) bindSymbol_l(handle, #name, k_##name);
+ BIND_SYMBOL(ApexCodec_Component_create);
+ BIND_SYMBOL(ApexCodec_Component_destroy);
+ BIND_SYMBOL(ApexCodec_Component_flush);
+ BIND_SYMBOL(ApexCodec_Component_getConfigurable);
+ BIND_SYMBOL(ApexCodec_Component_process);
+ BIND_SYMBOL(ApexCodec_Component_start);
+ BIND_SYMBOL(ApexCodec_Component_reset);
+ BIND_SYMBOL(ApexCodec_Configurable_config);
+ BIND_SYMBOL(ApexCodec_Configurable_query);
+ BIND_SYMBOL(ApexCodec_Configurable_querySupportedParams);
+ BIND_SYMBOL(ApexCodec_Configurable_querySupportedValues);
+ BIND_SYMBOL(ApexCodec_GetComponentStore);
+ BIND_SYMBOL(ApexCodec_ParamDescriptors_getDescriptor);
+ BIND_SYMBOL(ApexCodec_ParamDescriptors_getIndices);
+ BIND_SYMBOL(ApexCodec_ParamDescriptors_release);
+ BIND_SYMBOL(ApexCodec_SettingResults_getResultAtIndex);
+ BIND_SYMBOL(ApexCodec_SettingResults_release);
+ BIND_SYMBOL(ApexCodec_SupportedValues_getTypeAndValues);
+ BIND_SYMBOL(ApexCodec_SupportedValues_release);
+ BIND_SYMBOL(ApexCodec_Traits_get);
+#undef BIND_SYMBOL
+
+ // Check every symbol is bound.
+ for (int i = 0; i < k_MethodCount; ++i) {
+ if (mMethods[i] == nullptr) {
+ ALOGI("Uninitialized method in libapexcodecs_lazy at index: %d", i);
+ return false;
+ }
+ }
+ mInit = true;
+ return true;
+ }
+
+ RWLock mLock;
+ // Table of methods pointers in libapexcodecs APIs.
+ void* mMethods[k_MethodCount];
+ bool mInit{false};
+};
+
+} // anonymous namespace
+
+#define INVOKE_METHOD(name, returnIfNull, args...) \
+ do { \
+ void* method = ApexCodecsLazyLoader::Get().getMethodAt(k_##name); \
+ if (!method) return (returnIfNull); \
+ return reinterpret_cast<decltype(&name)>(method)(args); \
+ } while (0)
+
+//
+// Forwarding for methods in ApexCodecs.h.
+//
+
+ApexCodec_ComponentStore *ApexCodec_GetComponentStore() {
+ INVOKE_METHOD(ApexCodec_GetComponentStore, nullptr);
+}
+
+ApexCodec_ComponentTraits *ApexCodec_Traits_get(
+ ApexCodec_ComponentStore *store, size_t index) {
+ INVOKE_METHOD(ApexCodec_Traits_get, nullptr, store, index);
+}
+
+ApexCodec_Status ApexCodec_Component_create(
+ ApexCodec_ComponentStore *store, const char *name, ApexCodec_Component **comp) {
+ INVOKE_METHOD(ApexCodec_Component_create, APEXCODEC_STATUS_OMITTED, store, name, comp);
+}
+
+void ApexCodec_Component_destroy(ApexCodec_Component *comp) {
+ INVOKE_METHOD(ApexCodec_Component_destroy, void(), comp);
+}
+
+ApexCodec_Status ApexCodec_Component_start(ApexCodec_Component *comp) {
+ INVOKE_METHOD(ApexCodec_Component_start, APEXCODEC_STATUS_OMITTED, comp);
+}
+
+ApexCodec_Status ApexCodec_Component_flush(ApexCodec_Component *comp) {
+ INVOKE_METHOD(ApexCodec_Component_flush, APEXCODEC_STATUS_OMITTED, comp);
+}
+
+ApexCodec_Status ApexCodec_Component_reset(ApexCodec_Component *comp) {
+ INVOKE_METHOD(ApexCodec_Component_reset, APEXCODEC_STATUS_OMITTED, comp);
+}
+
+ApexCodec_Configurable *ApexCodec_Component_getConfigurable(
+ ApexCodec_Component *comp) {
+ INVOKE_METHOD(ApexCodec_Component_getConfigurable, nullptr, comp);
+}
+
+ApexCodec_Status ApexCodec_SupportedValues_getTypeAndValues(
+ ApexCodec_SupportedValues *supportedValues,
+ ApexCodec_SupportedValuesType *type,
+ ApexCodec_SupportedValuesNumberType *numberType,
+ ApexCodec_Value **values,
+ uint32_t *numValues) {
+ INVOKE_METHOD(ApexCodec_SupportedValues_getTypeAndValues, APEXCODEC_STATUS_OMITTED,
+ supportedValues, type, numberType, values, numValues);
+}
+
+void ApexCodec_SupportedValues_release(ApexCodec_SupportedValues *values) {
+ INVOKE_METHOD(ApexCodec_SupportedValues_release, void(), values);
+}
+
+ApexCodec_Status ApexCodec_SettingResults_getResultAtIndex(
+ ApexCodec_SettingResults *results,
+ size_t index,
+ ApexCodec_SettingResultFailure *failure,
+ ApexCodec_ParamFieldValues *field,
+ ApexCodec_ParamFieldValues **conflicts,
+ size_t *numConflicts) {
+ INVOKE_METHOD(ApexCodec_SettingResults_getResultAtIndex, APEXCODEC_STATUS_OMITTED,
+ results, index, failure, field, conflicts, numConflicts);
+}
+
+void ApexCodec_SettingResults_release(ApexCodec_SettingResults *results) {
+ INVOKE_METHOD(ApexCodec_SettingResults_release, void(), results);
+}
+
+ApexCodec_Status ApexCodec_Component_process(
+ ApexCodec_Component *comp,
+ const ApexCodec_Buffer *input,
+ ApexCodec_Buffer *output,
+ size_t *consumed,
+ size_t *produced) {
+ INVOKE_METHOD(ApexCodec_Component_process, APEXCODEC_STATUS_OMITTED,
+ comp, input, output, consumed, produced);
+}
+
+ApexCodec_Status ApexCodec_Configurable_config(
+ ApexCodec_Configurable *comp,
+ ApexCodec_LinearBuffer *config,
+ ApexCodec_SettingResults **results) {
+ INVOKE_METHOD(ApexCodec_Configurable_config, APEXCODEC_STATUS_OMITTED, comp, config, results);
+}
+
+ApexCodec_Status ApexCodec_Configurable_query(
+ ApexCodec_Configurable *comp,
+ uint32_t indices[],
+ size_t numIndices,
+ ApexCodec_LinearBuffer *config,
+ size_t *writtenOrRequested) {
+ INVOKE_METHOD(ApexCodec_Configurable_query, APEXCODEC_STATUS_OMITTED,
+ comp, indices, numIndices, config, writtenOrRequested);
+}
+
+ApexCodec_Status ApexCodec_ParamDescriptors_getIndices(
+ ApexCodec_ParamDescriptors *descriptors,
+ uint32_t **indices,
+ size_t *numIndices) {
+ INVOKE_METHOD(ApexCodec_ParamDescriptors_getIndices, APEXCODEC_STATUS_OMITTED,
+ descriptors, indices, numIndices);
+}
+
+ApexCodec_Status ApexCodec_ParamDescriptors_getDescriptor(
+ ApexCodec_ParamDescriptors *descriptors,
+ uint32_t index,
+ ApexCodec_ParamAttribute *attr,
+ const char **name,
+ uint32_t **dependencies,
+ size_t *numDependencies) {
+ INVOKE_METHOD(ApexCodec_ParamDescriptors_getDescriptor, APEXCODEC_STATUS_OMITTED,
+ descriptors, index, attr, name, dependencies, numDependencies);
+}
+
+ApexCodec_Status ApexCodec_ParamDescriptors_release(
+ ApexCodec_ParamDescriptors *descriptors) {
+ INVOKE_METHOD(ApexCodec_ParamDescriptors_release, APEXCODEC_STATUS_OMITTED, descriptors);
+}
+
+ApexCodec_Status ApexCodec_Configurable_querySupportedParams(
+ ApexCodec_Configurable *comp,
+ ApexCodec_ParamDescriptors **descriptors) {
+ INVOKE_METHOD(ApexCodec_Configurable_querySupportedParams, APEXCODEC_STATUS_OMITTED,
+ comp, descriptors);
+}
+
+ApexCodec_Status ApexCodec_Configurable_querySupportedValues(
+ ApexCodec_Configurable *comp,
+ ApexCodec_SupportedValuesQuery *queries,
+ size_t numQueries) {
+ INVOKE_METHOD(ApexCodec_Configurable_querySupportedValues, APEXCODEC_STATUS_OMITTED,
+ comp, queries, numQueries);
+}
diff --git a/media/codec2/hal/client/client.cpp b/media/codec2/hal/client/client.cpp
index 6348e42..9ee9b9e 100644
--- a/media/codec2/hal/client/client.cpp
+++ b/media/codec2/hal/client/client.cpp
@@ -20,6 +20,8 @@
#include <android-base/logging.h>
#include <utils/Trace.h>
+#include <android_media_codec.h>
+
#include <codec2/aidl/GraphicBufferAllocator.h>
#include <codec2/common/HalSelection.h>
#include <codec2/hidl/client.h>
@@ -55,7 +57,9 @@
#include <android/binder_ibinder.h>
#include <android/binder_manager.h>
#include <android-base/properties.h>
+#include <android-base/scopeguard.h>
#include <android-base/stringprintf.h>
+#include <apex/ApexCodecs.h>
#include <bufferpool/ClientManager.h>
#include <bufferpool2/ClientManager.h>
#include <codec2/aidl/BufferTypes.h>
@@ -64,14 +68,14 @@
#include <codec2/hidl/1.1/types.h>
#include <codec2/hidl/1.2/types.h>
#include <codec2/hidl/output.h>
-
#include <cutils/native_handle.h>
#include <gui/bufferqueue/2.0/B2HGraphicBufferProducer.h>
#include <gui/bufferqueue/2.0/H2BGraphicBufferProducer.h>
#include <hardware/gralloc.h> // for GRALLOC_USAGE_*
#include <hidl/HidlSupport.h>
-#include <system/window.h> // for NATIVE_WINDOW_QUERY_*
#include <media/stagefright/foundation/ADebug.h> // for asString(status_t)
+#include <private/android/AHardwareBufferHelpers.h>
+#include <system/window.h> // for NATIVE_WINDOW_QUERY_*
#include <deque>
#include <iterator>
@@ -799,6 +803,386 @@
return status;
}
+// Codec2ConfigurableClient::ApexImpl
+
+struct Codec2ConfigurableClient::ApexImpl : public Codec2ConfigurableClient::ImplBase {
+ ApexImpl(ApexCodec_Configurable *base, const C2String &name);
+
+ const C2String& getName() const override {
+ return mName;
+ }
+
+ c2_status_t query(
+ const std::vector<C2Param*>& stackParams,
+ const std::vector<C2Param::Index> &heapParamIndices,
+ c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2Param>>* const heapParams) const override;
+
+ c2_status_t config(
+ const std::vector<C2Param*> ¶ms,
+ c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2SettingResult>>* const failures) override;
+
+ c2_status_t querySupportedParams(
+ std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
+ ) const override;
+
+ c2_status_t querySupportedValues(
+ std::vector<C2FieldSupportedValuesQuery>& fields,
+ c2_blocking_t mayBlock) const override;
+
+private:
+ ApexCodec_Configurable* mBase;
+ const C2String mName;
+};
+
+Codec2ConfigurableClient::ApexImpl::ApexImpl(ApexCodec_Configurable *base, const C2String &name)
+ : mBase{base},
+ mName{name} {
+}
+
+c2_status_t Codec2ConfigurableClient::ApexImpl::query(
+ const std::vector<C2Param*> &stackParams,
+ const std::vector<C2Param::Index> &heapParamIndices,
+ [[maybe_unused]] c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2Param>>* const heapParams) const {
+ if (mBase == nullptr) {
+ return C2_OMITTED;
+ }
+
+ if (__builtin_available(android 36, *)) {
+ std::vector<uint32_t> indices(
+ stackParams.size() + heapParamIndices.size());
+ size_t numIndices = 0;
+ for (C2Param* const& stackParam : stackParams) {
+ if (!stackParam) {
+ LOG(WARNING) << "query -- null stack param encountered.";
+ continue;
+ }
+ indices[numIndices++] = uint32_t(stackParam->index());
+ }
+ size_t numStackIndices = numIndices;
+ for (const C2Param::Index& index : heapParamIndices) {
+ indices[numIndices++] = uint32_t(index);
+ }
+ indices.resize(numIndices);
+ if (heapParams) {
+ heapParams->reserve(heapParams->size() + numIndices);
+ }
+ if (numIndices == 0) {
+ return C2_OK;
+ }
+ thread_local std::vector<uint8_t> configBuffer(1024);
+ if (configBuffer.capacity() < numIndices * 16u) {
+ configBuffer.resize(numIndices * 16u);
+ }
+ ApexCodec_LinearBuffer config{configBuffer.data(), configBuffer.capacity()};
+ size_t writtenOrRequested = 0;
+ ApexCodec_Status status = ApexCodec_Configurable_query(
+ mBase, indices.data(), indices.size(), &config, &writtenOrRequested);
+ if (status == APEXCODEC_STATUS_NO_MEMORY) {
+ size_t requested = writtenOrRequested;
+ configBuffer.resize(align(requested, 1024));
+ config.data = configBuffer.data();
+ config.size = configBuffer.capacity();
+ status = ApexCodec_Configurable_query(
+ mBase, indices.data(), indices.size(), &config, &writtenOrRequested);
+ }
+ size_t written = writtenOrRequested;
+ if (status != APEXCODEC_STATUS_OK && status != APEXCODEC_STATUS_BAD_INDEX) {
+ written = 0;
+ }
+ configBuffer.resize(written);
+ std::vector<C2Param*> paramPointers;
+ if (!::android::parseParamsBlob(¶mPointers, configBuffer)) {
+ LOG(ERROR) << "query -- error while parsing params.";
+ return C2_CORRUPTED;
+ }
+ size_t i = 0;
+ size_t numQueried = 0;
+ for (auto it = paramPointers.begin(); it != paramPointers.end(); ) {
+ C2Param* paramPointer = *it;
+ if (numStackIndices > 0) {
+ --numStackIndices;
+ if (!paramPointer) {
+ LOG(DEBUG) << "query -- null stack param.";
+ ++it;
+ continue;
+ }
+ for (; i < stackParams.size() && !stackParams[i]; ) {
+ ++i;
+ }
+ if (i >= stackParams.size()) {
+ LOG(ERROR) << "query -- unexpected error.";
+ status = APEXCODEC_STATUS_CORRUPTED;
+ break;
+ }
+ if (stackParams[i]->index() != paramPointer->index()) {
+ LOG(DEBUG) << "query -- param skipped: "
+ "index = "
+ << stackParams[i]->index() << ".";
+ stackParams[i++]->invalidate();
+ // this means that the param could not be queried.
+ // signalling C2_BAD_INDEX to the client.
+ status = APEXCODEC_STATUS_BAD_INDEX;
+ continue;
+ }
+ if (stackParams[i++]->updateFrom(*paramPointer)) {
+ ++numQueried;
+ } else {
+ LOG(WARNING) << "query -- param update failed: "
+ "index = "
+ << paramPointer->index() << ".";
+ }
+ } else {
+ if (!paramPointer) {
+ LOG(DEBUG) << "query -- null heap param.";
+ ++it;
+ continue;
+ }
+ if (!heapParams) {
+ LOG(WARNING) << "query -- "
+ "unexpected extra stack param.";
+ } else {
+ heapParams->emplace_back(C2Param::Copy(*paramPointer));
+ ++numQueried;
+ }
+ }
+ ++it;
+ }
+ if (status == APEXCODEC_STATUS_OK && indices.size() != numQueried) {
+ status = APEXCODEC_STATUS_BAD_INDEX;
+ }
+ return (c2_status_t)status;
+ } else {
+ return C2_OMITTED;
+ }
+}
+
+namespace {
+struct ParamOrField : public C2ParamField {
+ explicit ParamOrField(const ApexCodec_ParamFieldValues& field)
+ : C2ParamField(field.index, field.offset, field.size) {}
+};
+
+static bool FromApex(
+ ApexCodec_SupportedValues *apexValues,
+ C2FieldSupportedValues* c2Values) {
+ if (__builtin_available(android 36, *)) {
+ if (apexValues == nullptr) {
+ c2Values->type = C2FieldSupportedValues::EMPTY;
+ return true;
+ }
+ ApexCodec_SupportedValuesType type = APEXCODEC_SUPPORTED_VALUES_EMPTY;
+ ApexCodec_SupportedValuesNumberType numberType = APEXCODEC_SUPPORTED_VALUES_TYPE_NONE;
+ ApexCodec_Value* values = nullptr;
+ uint32_t numValues = 0;
+ ApexCodec_SupportedValues_getTypeAndValues(
+ apexValues, &type, &numberType, &values, &numValues);
+ c2Values->type = (C2FieldSupportedValues::type_t)type;
+ std::function<C2Value::Primitive(const ApexCodec_Value &)> getPrimitive;
+ switch (numberType) {
+ case APEXCODEC_SUPPORTED_VALUES_TYPE_NONE:
+ getPrimitive = [](const ApexCodec_Value &) -> C2Value::Primitive {
+ return C2Value::Primitive();
+ };
+ break;
+ case APEXCODEC_SUPPORTED_VALUES_TYPE_INT32:
+ getPrimitive = [](const ApexCodec_Value &value) -> C2Value::Primitive {
+ return C2Value::Primitive(value.i32);
+ };
+ break;
+ case APEXCODEC_SUPPORTED_VALUES_TYPE_UINT32:
+ getPrimitive = [](const ApexCodec_Value &value) -> C2Value::Primitive {
+ return C2Value::Primitive(value.u32);
+ };
+ break;
+ case APEXCODEC_SUPPORTED_VALUES_TYPE_INT64:
+ getPrimitive = [](const ApexCodec_Value &value) -> C2Value::Primitive {
+ return C2Value::Primitive(value.i64);
+ };
+ break;
+ case APEXCODEC_SUPPORTED_VALUES_TYPE_UINT64:
+ getPrimitive = [](const ApexCodec_Value &value) -> C2Value::Primitive {
+ return C2Value::Primitive(value.u64);
+ };
+ break;
+ case APEXCODEC_SUPPORTED_VALUES_TYPE_FLOAT:
+ getPrimitive = [](const ApexCodec_Value &value) -> C2Value::Primitive {
+ return C2Value::Primitive(value.f);
+ };
+ break;
+ default:
+ LOG(ERROR) << "Unsupported number type: " << numberType;
+ return false;
+ }
+ switch (type) {
+ case APEXCODEC_SUPPORTED_VALUES_EMPTY:
+ break;
+ case APEXCODEC_SUPPORTED_VALUES_RANGE:
+ c2Values->range.min = getPrimitive(values[0]);
+ c2Values->range.max = getPrimitive(values[1]);
+ c2Values->range.step = getPrimitive(values[2]);
+ c2Values->range.num = getPrimitive(values[3]);
+ c2Values->range.denom = getPrimitive(values[4]);
+ break;
+ case APEXCODEC_SUPPORTED_VALUES_VALUES:
+ case APEXCODEC_SUPPORTED_VALUES_FLAGS:
+ c2Values->values.clear();
+ for (uint32_t i = 0; i < numValues; ++i) {
+ c2Values->values.push_back(getPrimitive(values[i]));
+ }
+ break;
+ default:
+ LOG(ERROR) << "Unsupported supported values type: " << type;
+ return false;
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+} // anonymous namespace
+
+c2_status_t Codec2ConfigurableClient::ApexImpl::config(
+ const std::vector<C2Param*> ¶ms,
+ c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
+ (void)mayBlock;
+ if (mBase == nullptr) {
+ return C2_OMITTED;
+ }
+
+ if (__builtin_available(android 36, *)) {
+ std::vector<uint8_t> configBuffer;
+ if (!::android::_createParamsBlob(&configBuffer, params)) {
+ LOG(ERROR) << "config -- bad input.";
+ return C2_TRANSACTION_FAILED;
+ }
+ ApexCodec_SettingResults* result = nullptr;
+ ApexCodec_LinearBuffer config{configBuffer.data(), configBuffer.size()};
+ ApexCodec_Status status = ApexCodec_Configurable_config(
+ mBase, &config, &result);
+ base::ScopeGuard guard([result] {
+ if (result) {
+ ApexCodec_SettingResults_release(result);
+ }
+ });
+ size_t index = 0;
+ ApexCodec_SettingResultFailure failure;
+ ApexCodec_ParamFieldValues field;
+ ApexCodec_ParamFieldValues* conflicts = nullptr;
+ size_t numConflicts = 0;
+ ApexCodec_Status getResultStatus = ApexCodec_SettingResults_getResultAtIndex(
+ result, 0, &failure, &field, &conflicts, &numConflicts);
+ while (getResultStatus == APEXCODEC_STATUS_OK) {
+ std::unique_ptr<C2SettingResult> settingResult;
+ settingResult.reset(new C2SettingResult{
+ C2SettingResult::Failure(failure), C2ParamFieldValues(ParamOrField(field)), {}
+ });
+ // TODO: settingResult->field.values = ?
+ for (size_t i = 0; i < numConflicts; ++i) {
+ settingResult->conflicts.emplace_back(ParamOrField(conflicts[i]));
+ C2ParamFieldValues& conflict = settingResult->conflicts.back();
+ conflict.values = std::make_unique<C2FieldSupportedValues>();
+ FromApex(conflicts[i].values, conflict.values.get());
+ }
+ failures->push_back(std::move(settingResult));
+ getResultStatus = ApexCodec_SettingResults_getResultAtIndex(
+ result, ++index, &failure, &field, &conflicts, &numConflicts);
+ }
+ if (!::android::updateParamsFromBlob(params, configBuffer)) {
+ LOG(ERROR) << "config -- "
+ << "failed to parse returned params.";
+ status = APEXCODEC_STATUS_CORRUPTED;
+ }
+ return (c2_status_t)status;
+ } else {
+ return C2_OMITTED;
+ }
+}
+
+c2_status_t Codec2ConfigurableClient::ApexImpl::querySupportedParams(
+ std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const {
+ if (mBase == nullptr) {
+ return C2_OMITTED;
+ }
+
+ if (__builtin_available(android 36, *)) {
+ // TODO: Cache and query properly!
+ ApexCodec_ParamDescriptors* paramDescs = nullptr;
+ ApexCodec_Configurable_querySupportedParams(mBase, ¶mDescs);
+ base::ScopeGuard guard([paramDescs] {
+ if (paramDescs) {
+ ApexCodec_ParamDescriptors_release(paramDescs);
+ }
+ });
+ uint32_t *indices = nullptr;
+ size_t numIndices = 0;
+ ApexCodec_Status status = ApexCodec_ParamDescriptors_getIndices(
+ paramDescs, &indices, &numIndices);
+ if (status != APEXCODEC_STATUS_OK) {
+ return (c2_status_t)status;
+ }
+ if (numIndices > 0) {
+ for (int i = 0; i < numIndices; ++i) {
+ uint32_t index = indices[i];
+ ApexCodec_ParamAttribute attr = (ApexCodec_ParamAttribute)0;
+ const char* name = nullptr;
+ uint32_t* dependencies = nullptr;
+ size_t numDependencies = 0;
+ ApexCodec_Status status = ApexCodec_ParamDescriptors_getDescriptor(
+ paramDescs, index, &attr, &name, &dependencies, &numDependencies);
+ if (status != APEXCODEC_STATUS_OK) {
+ LOG(WARNING) << "querySupportedParams -- "
+ << "failed to get descriptor for index "
+ << std::hex << index << std::dec << " with status " << status;
+ continue;
+ }
+ params->push_back(std::make_shared<C2ParamDescriptor>(
+ C2Param::Index(index), C2ParamDescriptor::attrib_t(attr), name,
+ std::vector<C2Param::Index>(dependencies, dependencies + numDependencies)));
+ }
+ }
+ return (c2_status_t)status;
+ } else {
+ return C2_OMITTED;
+ }
+}
+
+c2_status_t Codec2ConfigurableClient::ApexImpl::querySupportedValues(
+ std::vector<C2FieldSupportedValuesQuery>& fields,
+ [[maybe_unused]] c2_blocking_t mayBlock) const {
+ if (mBase == nullptr) {
+ return C2_OMITTED;
+ }
+
+ if (__builtin_available(android 36, *)) {
+ std::vector<ApexCodec_SupportedValuesQuery> queries(fields.size());
+ for (size_t i = 0; i < fields.size(); ++i) {
+ queries[i].index = _C2ParamInspector::GetIndex(fields[i].field());
+ queries[i].offset = _C2ParamInspector::GetOffset(fields[i].field());
+ queries[i].type = (ApexCodec_SupportedValuesQueryType)fields[i].type();
+ queries[i].status = APEXCODEC_STATUS_OK;
+ queries[i].values = nullptr;
+ }
+ ApexCodec_Status status = ApexCodec_Configurable_querySupportedValues(
+ mBase, queries.data(), queries.size());
+ for (size_t i = 0; i < fields.size(); ++i) {
+ fields[i].status = (c2_status_t)queries[i].status;
+ FromApex(queries[i].values, &fields[i].values);
+ if (queries[i].values) {
+ ApexCodec_SupportedValues_release(queries[i].values);
+ queries[i].values = nullptr;
+ }
+ }
+ return (c2_status_t)status;
+ } else {
+ return C2_OMITTED;
+ }
+}
+
// Codec2ConfigurableClient
Codec2ConfigurableClient::Codec2ConfigurableClient(const sp<HidlBase> &hidlBase)
@@ -810,6 +1194,11 @@
: mImpl(new Codec2ConfigurableClient::AidlImpl(aidlBase)) {
}
+Codec2ConfigurableClient::Codec2ConfigurableClient(
+ ApexCodec_Configurable *apexBase, const C2String &name)
+ : mImpl(new Codec2ConfigurableClient::ApexImpl(apexBase, name)) {
+}
+
const C2String& Codec2ConfigurableClient::getName() const {
return mImpl->getName();
}
@@ -1035,6 +1424,393 @@
};
+// Codec2Client::Component::ApexHandler
+class Codec2Client::Component::ApexHandler {
+public:
+ ApexHandler(ApexCodec_Component *apexComponent,
+ const std::shared_ptr<Listener> &listener,
+ const std::shared_ptr<Component> &comp)
+ : mApexComponent(apexComponent),
+ mListener(listener),
+ mComponent(comp),
+ mStopped(false),
+ mOutputBufferType(APEXCODEC_BUFFER_TYPE_INVALID) {
+ }
+
+ void start() {
+ std::shared_ptr<Component> comp = mComponent.lock();
+ if (!comp) {
+ LOG(ERROR) << "ApexHandler::start -- component died.";
+ return;
+ }
+ C2ComponentDomainSetting domain;
+ C2ComponentKindSetting kind;
+ c2_status_t status = comp->query({&domain, &kind}, {}, C2_MAY_BLOCK, {});
+ if (status != C2_OK) {
+ LOG(ERROR) << "ApexHandler::start -- failed to query component domain and kind";
+ return;
+ }
+ if (kind.value != C2Component::KIND_DECODER
+ && kind.value != C2Component::KIND_ENCODER) {
+ LOG(ERROR) << "ApexHandler::start -- unrecognized component kind " << kind.value;
+ return;
+ }
+ ApexCodec_BufferType outputBufferType = APEXCODEC_BUFFER_TYPE_INVALID;
+ if (domain.value == C2Component::DOMAIN_AUDIO) {
+ // For both encoders and decoders the output buffer type is linear.
+ outputBufferType = APEXCODEC_BUFFER_TYPE_LINEAR;
+ } else if (domain.value == C2Component::DOMAIN_VIDEO
+ || domain.value == C2Component::DOMAIN_IMAGE) {
+ // For video / image domain the decoder outputs a graphic buffer, and the encoder
+ // outputs a linear buffer.
+ outputBufferType = (kind.value == C2Component::KIND_DECODER)
+ ? APEXCODEC_BUFFER_TYPE_GRAPHIC : APEXCODEC_BUFFER_TYPE_LINEAR;
+ } else {
+ LOG(ERROR) << "ApexHandler::start -- unrecognized component domain " << domain.value;
+ return;
+ }
+ {
+ std::unique_lock<std::mutex> l(mMutex);
+ mStopped = false;
+ mOutputBufferType = outputBufferType;
+ }
+ mThread = std::thread([this]() {
+ run();
+ });
+ }
+
+ void queue(std::list<std::unique_ptr<C2Work>>& workItems) {
+ std::unique_lock<std::mutex> l(mMutex);
+ mWorkQueue.splice(mWorkQueue.end(), workItems);
+ mCondition.notify_all();
+ }
+
+ void stop() {
+ std::unique_lock<std::mutex> l(mMutex);
+ mStopped = true;
+ mCondition.notify_all();
+ l.unlock();
+ mThread.join();
+ }
+
+private:
+ void run() {
+ while (true) {
+ std::unique_lock<std::mutex> l(mMutex);
+ mCondition.wait(l, [this]() {
+ return !mWorkQueue.empty() || mStopped;
+ });
+ if (mStopped) {
+ break;
+ }
+ if (mWorkQueue.empty()) {
+ continue;
+ }
+ std::list<std::unique_ptr<C2Work>> workItems;
+ mWorkQueue.swap(workItems);
+ for (std::unique_ptr<C2Work>& workItem : workItems) {
+ if (mStopped) {
+ break;
+ }
+ l.unlock();
+ handleWork(std::move(workItem));
+ l.lock();
+ }
+ }
+ mWorkQueue.clear();
+ mWorkMap.clear();
+ }
+
+ void handleWork(std::unique_ptr<C2Work> &&workItem) {
+ if (__builtin_available(android 36, *)) {
+ std::shared_ptr<Listener> listener = mListener.lock();
+ if (!listener) {
+ LOG(DEBUG) << "handleWork -- listener died.";
+ return;
+ }
+ ApexCodec_Buffer input;
+ input.flags = (ApexCodec_BufferFlags)workItem->input.flags;
+ input.frameIndex = workItem->input.ordinal.frameIndex.peekll();
+ input.timestampUs = workItem->input.ordinal.timestamp.peekll();
+
+ if (workItem->input.buffers.size() > 1) {
+ LOG(ERROR) << "handleWork -- input buffer size is "
+ << workItem->input.buffers.size();
+ return;
+ }
+ std::shared_ptr<C2Buffer> buffer;
+ std::optional<C2ReadView> linearView;
+ if (!workItem->input.buffers.empty()) {
+ buffer = workItem->input.buffers[0];
+ }
+ if (!FillMemory(buffer, &input, &linearView)) {
+ LOG(ERROR) << "handleWork -- failed to map input";
+ return;
+ }
+
+ std::vector<uint8_t> configUpdatesVector;
+ if (!_createParamsBlob(&configUpdatesVector, workItem->input.configUpdate)) {
+ listener->onError(mComponent, C2_CORRUPTED);
+ return;
+ }
+ input.configUpdates.data = configUpdatesVector.data();
+ input.configUpdates.size = configUpdatesVector.size();
+ mWorkMap.insert_or_assign(
+ workItem->input.ordinal.frameIndex.peekll(), std::move(workItem));
+
+ std::list<std::unique_ptr<C2Work>> workItems;
+ bool inputDrained = false;
+ while (!inputDrained) {
+ ApexCodec_Buffer output;
+ std::shared_ptr<C2LinearBlock> linearBlock;
+ std::optional<C2WriteView> linearView;
+ std::shared_ptr<C2GraphicBlock> graphicBlock;
+ allocOutputBuffer(&output, &linearBlock, &linearView, &graphicBlock);
+ size_t consumed = 0;
+ size_t produced = 0;
+ ApexCodec_Status status = ApexCodec_Component_process(
+ mApexComponent, &input, &output, &consumed, &produced);
+ if (status == APEXCODEC_STATUS_NO_MEMORY) {
+ continue;
+ }
+ if (produced > 0) {
+ auto it = mWorkMap.find(output.frameIndex);
+ std::unique_ptr<C2Work> outputWorkItem;
+ if (it != mWorkMap.end()) {
+ if (output.flags & APEXCODEC_FLAG_INCOMPLETE) {
+ outputWorkItem = std::make_unique<C2Work>();
+ outputWorkItem->input.ordinal = it->second->input.ordinal;
+ outputWorkItem->input.flags = it->second->input.flags;
+ } else {
+ outputWorkItem = std::move(it->second);
+ mWorkMap.erase(it);
+ }
+ } else {
+ LOG(WARNING) << "handleWork -- no work item found for output frame index "
+ << output.frameIndex;
+ outputWorkItem = std::make_unique<C2Work>();
+ outputWorkItem->input.ordinal.frameIndex = output.frameIndex;
+ outputWorkItem->input.ordinal.timestamp = output.timestampUs;
+ }
+ outputWorkItem->worklets.emplace_back(new C2Worklet);
+ const std::unique_ptr<C2Worklet> &worklet = outputWorkItem->worklets.front();
+ if (worklet == nullptr) {
+ LOG(ERROR) << "handleWork -- output work item has null worklet";
+ return;
+ }
+ worklet->output.ordinal.frameIndex = output.frameIndex;
+ worklet->output.ordinal.timestamp = output.timestampUs;
+ // non-owning hidl_vec<> to wrap around the output config updates
+ hidl_vec<uint8_t> outputConfigUpdates;
+ outputConfigUpdates.setToExternal(
+ output.configUpdates.data, output.configUpdates.size);
+ std::vector<C2Param*> outputConfigUpdatePtrs;
+ parseParamsBlob(&outputConfigUpdatePtrs, outputConfigUpdates);
+ worklet->output.configUpdate.clear();
+ std::ranges::transform(
+ outputConfigUpdatePtrs,
+ std::back_inserter(worklet->output.configUpdate),
+ [](C2Param* param) { return C2Param::Copy(*param); });
+ worklet->output.flags = (C2FrameData::flags_t)output.flags;
+
+ workItems.push_back(std::move(outputWorkItem));
+ }
+
+ // determine whether the input buffer is drained
+ if (input.type == APEXCODEC_BUFFER_TYPE_LINEAR) {
+ if (input.memory.linear.size < consumed) {
+ LOG(WARNING) << "handleWork -- component consumed more bytes "
+ << "than the input buffer size";
+ inputDrained = true;
+ } else {
+ input.memory.linear.data += consumed;
+ input.memory.linear.size -= consumed;
+ }
+ } else if (input.type == APEXCODEC_BUFFER_TYPE_GRAPHIC) {
+ inputDrained = (consumed > 0);
+ }
+ }
+
+ if (!workItems.empty()) {
+ listener->onWorkDone(mComponent, workItems);
+ }
+ }
+ }
+
+ bool ensureBlockPool() {
+ std::shared_ptr<Component> comp = mComponent.lock();
+ if (!comp) {
+ return false;
+ }
+ std::vector<std::unique_ptr<C2Param>> heapParams;
+ comp->query({}, {C2PortBlockPoolsTuning::output::PARAM_TYPE}, C2_MAY_BLOCK, &heapParams);
+ if (heapParams.size() != 1) {
+ return false;
+ }
+ const C2Param* param = heapParams[0].get();
+ if (param->type() != C2PortBlockPoolsTuning::output::PARAM_TYPE) {
+ return false;
+ }
+ const C2PortBlockPoolsTuning::output *blockPools =
+ static_cast<const C2PortBlockPoolsTuning::output *>(param);
+ if (blockPools->flexCount() == 0) {
+ return false;
+ }
+ C2BlockPool::local_id_t blockPoolId = blockPools->m.values[0];
+ if (mBlockPool && mBlockPool->getLocalId() == blockPoolId) {
+ // no need to update
+ return true;
+ }
+ return C2_OK == GetCodec2BlockPool(blockPoolId, nullptr, &mBlockPool);
+ }
+
+ void allocOutputBuffer(
+ ApexCodec_Buffer* output,
+ std::shared_ptr<C2LinearBlock> *linearBlock,
+ std::optional<C2WriteView> *linearView,
+ std::shared_ptr<C2GraphicBlock> *graphicBlock) {
+ if (mOutputBufferType == APEXCODEC_BUFFER_TYPE_LINEAR) {
+ if (!ensureBlockPool()) {
+ return;
+ }
+ {
+ std::shared_ptr<Component> comp = mComponent.lock();
+ if (!comp) {
+ return;
+ }
+ C2StreamMaxBufferSizeInfo::output maxBufferSize(0u /* stream */);
+ comp->query({&maxBufferSize}, {}, C2_MAY_BLOCK, {});
+ mLinearBlockCapacity = maxBufferSize ? maxBufferSize.value : 1024 * 1024;
+ }
+ output->type = APEXCODEC_BUFFER_TYPE_LINEAR;
+ c2_status_t status = mBlockPool->fetchLinearBlock(
+ mLinearBlockCapacity,
+ C2MemoryUsage(C2MemoryUsage::CPU_READ | C2MemoryUsage::CPU_WRITE),
+ linearBlock);
+ if (!(*linearBlock)) {
+ return;
+ }
+ linearView->emplace((*linearBlock)->map().get());
+ if ((*linearView)->error() != C2_OK) {
+ return;
+ }
+ output->memory.linear.data = (*linearView)->data();
+ output->memory.linear.size = (*linearView)->capacity();
+ } else if (mOutputBufferType == APEXCODEC_BUFFER_TYPE_GRAPHIC) {
+ if (!ensureBlockPool()) {
+ return;
+ }
+ {
+ std::shared_ptr<Component> comp = mComponent.lock();
+ if (!comp) {
+ return;
+ }
+ C2StreamMaxPictureSizeTuning::output maxPictureSize(0u /* stream */);
+ C2StreamPictureSizeInfo::output pictureSize(0u /* stream */);
+ C2StreamPixelFormatInfo::output pixelFormat(0u /* stream */);
+ comp->query({&maxPictureSize, &pictureSize, &pixelFormat}, {}, C2_MAY_BLOCK, {});
+ mWidth = maxPictureSize ? maxPictureSize.width : pictureSize.width;
+ mHeight = maxPictureSize ? maxPictureSize.height : pictureSize.height;
+ mFormat = pixelFormat ? pixelFormat.value : HAL_PIXEL_FORMAT_YCBCR_420_888;
+ }
+ output->type = APEXCODEC_BUFFER_TYPE_GRAPHIC;
+ c2_status_t status = mBlockPool->fetchGraphicBlock(
+ mWidth, mHeight, mFormat,
+ C2MemoryUsage(C2MemoryUsage::CPU_READ | C2MemoryUsage::CPU_WRITE),
+ graphicBlock);
+ if (!(*graphicBlock)) {
+ return;
+ }
+ const C2Handle *handle = (*graphicBlock)->handle();
+ uint32_t width, height, format, stride, igbp_slot, generation;
+ uint64_t usage, igbp_id;
+ _UnwrapNativeCodec2GrallocMetadata(
+ handle, &width, &height, &format, &usage, &stride, &generation,
+ &igbp_id, &igbp_slot);
+ native_handle_t *grallocHandle = UnwrapNativeCodec2GrallocHandle(handle);
+ sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
+ grallocHandle, GraphicBuffer::CLONE_HANDLE,
+ width, height, format, 1, usage, stride);
+ native_handle_delete(grallocHandle);
+ AHardwareBuffer *hardwareBuffer =
+ AHardwareBuffer_from_GraphicBuffer(graphicBuffer.get());
+ AHardwareBuffer_acquire(hardwareBuffer);
+ output->memory.graphic = hardwareBuffer;
+ } else {
+ LOG(ERROR) << "allocOutputBuffer -- unsupported output buffer type: "
+ << mOutputBufferType;
+ return;
+ }
+ }
+
+ static bool FillMemory(
+ const std::shared_ptr<C2Buffer>& buffer,
+ ApexCodec_Buffer* apexBuffer,
+ std::optional<C2ReadView>* linearView) {
+ if (buffer->data().type() == C2BufferData::LINEAR) {
+ apexBuffer->type = APEXCODEC_BUFFER_TYPE_LINEAR;
+ if (buffer->data().linearBlocks().empty()) {
+ apexBuffer->memory.linear.data = nullptr;
+ apexBuffer->memory.linear.size = 0;
+ return true;
+ } else if (buffer->data().linearBlocks().size() > 1) {
+ return false;
+ }
+ linearView->emplace(buffer->data().linearBlocks().front().map().get());
+ if ((*linearView)->error() != C2_OK) {
+ return false;
+ }
+ apexBuffer->memory.linear.data = const_cast<uint8_t*>((*linearView)->data());
+ apexBuffer->memory.linear.size = (*linearView)->capacity();
+ return true;
+ } else if (buffer->data().type() == C2BufferData::GRAPHIC) {
+ apexBuffer->type = APEXCODEC_BUFFER_TYPE_GRAPHIC;
+ if (buffer->data().graphicBlocks().empty()) {
+ apexBuffer->memory.graphic = nullptr;
+ return true;
+ } else if (buffer->data().graphicBlocks().size() > 1) {
+ return false;
+ }
+ const C2Handle *handle = buffer->data().graphicBlocks().front().handle();
+ uint32_t width, height, format, stride, igbp_slot, generation;
+ uint64_t usage, igbp_id;
+ _UnwrapNativeCodec2GrallocMetadata(
+ handle, &width, &height, &format, &usage, &stride, &generation,
+ &igbp_id, &igbp_slot);
+ native_handle_t *grallocHandle = UnwrapNativeCodec2GrallocHandle(handle);
+ sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
+ grallocHandle, GraphicBuffer::CLONE_HANDLE,
+ width, height, format, 1, usage, stride);
+ native_handle_delete(grallocHandle);
+ AHardwareBuffer *hardwareBuffer =
+ AHardwareBuffer_from_GraphicBuffer(graphicBuffer.get());
+ AHardwareBuffer_acquire(hardwareBuffer);
+ apexBuffer->memory.graphic = hardwareBuffer;
+ return true;
+ }
+ return false;
+ }
+
+ ApexCodec_Component *mApexComponent;
+ std::weak_ptr<Listener> mListener;
+ std::weak_ptr<Component> mComponent;
+
+ std::thread mThread;
+ std::mutex mMutex;
+ std::condition_variable mCondition;
+ bool mStopped;
+ ApexCodec_BufferType mOutputBufferType;
+
+ size_t mLinearBlockCapacity;
+ uint32_t mWidth;
+ uint32_t mHeight;
+ uint32_t mFormat;
+
+ std::shared_ptr<C2BlockPool> mBlockPool;
+ std::list<std::unique_ptr<C2Work>> mWorkQueue;
+ std::map<uint64_t, std::unique_ptr<C2Work>> mWorkMap;
+};
+
// Codec2Client::Component::HidlBufferPoolSender
struct Codec2Client::Component::HidlBufferPoolSender :
hardware::media::c2::V1_1::utils::DefaultBufferPoolSender {
@@ -1168,6 +1944,13 @@
}
}
+Codec2Client::Codec2Client(ApexCodec_ComponentStore *base,
+ size_t serviceIndex)
+ : Configurable{nullptr, "android.componentStore.apexCodecs"},
+ mApexBase{base},
+ mServiceIndex{serviceIndex} {
+}
+
sp<Codec2Client::HidlBase> const& Codec2Client::getHidlBase() const {
return mHidlBase1_0;
}
@@ -1196,36 +1979,71 @@
const C2String& name,
const std::shared_ptr<Codec2Client::Listener>& listener,
std::shared_ptr<Codec2Client::Component>* const component) {
- if (mAidlBase) {
- std::shared_ptr<Component::AidlListener> aidlListener =
- Component::AidlListener::make<Component::AidlListener>();
- aidlListener->base = listener;
- std::shared_ptr<c2_aidl::IComponent> aidlComponent;
- ::ndk::ScopedAStatus transStatus = mAidlBase->createComponent(
- name,
- aidlListener,
- bufferpool2_aidl::implementation::ClientManager::getInstance(),
- &aidlComponent);
- c2_status_t status = GetC2Status(transStatus, "createComponent");
- if (status != C2_OK) {
- return status;
- } else if (!aidlComponent) {
- LOG(ERROR) << "createComponent(" << name.c_str()
- << ") -- null component.";
- return C2_CORRUPTED;
- }
- *component = std::make_shared<Codec2Client::Component>(aidlComponent);
- status = (*component)->setDeathListener((*component), listener);
- if (status != C2_OK) {
- LOG(ERROR) << "createComponent(" << name.c_str()
- << ") -- failed to set up death listener: "
- << status << ".";
- }
- (*component)->mAidlBufferPoolSender->setReceiver(mAidlHostPoolManager);
- aidlListener->component = *component;
- return status;
+ if (mApexBase) {
+ return createComponent_apex(name, listener, component);
+ } else if (mAidlBase) {
+ return createComponent_aidl(name, listener, component);
+ } else {
+ return createComponent_hidl(name, listener, component);
}
+}
+c2_status_t Codec2Client::createComponent_apex(
+ const C2String& name,
+ const std::shared_ptr<Codec2Client::Listener>& listener,
+ std::shared_ptr<Codec2Client::Component>* const component) {
+ if (__builtin_available(android 36, *)) {
+ ApexCodec_Component *apexComponent = nullptr;
+ ApexCodec_Status status = ApexCodec_Component_create(
+ mApexBase, name.c_str(), &apexComponent);
+ if (status != APEXCODEC_STATUS_OK) {
+ return (c2_status_t)status;
+ }
+ *component = std::make_shared<Codec2Client::Component>(apexComponent, name);
+ (*component)->initApexHandler(listener, *component);
+ return C2_OK;
+ } else {
+ return C2_OMITTED;
+ }
+}
+
+c2_status_t Codec2Client::createComponent_aidl(
+ const C2String& name,
+ const std::shared_ptr<Codec2Client::Listener>& listener,
+ std::shared_ptr<Codec2Client::Component>* const component) {
+ std::shared_ptr<Component::AidlListener> aidlListener =
+ Component::AidlListener::make<Component::AidlListener>();
+ aidlListener->base = listener;
+ std::shared_ptr<c2_aidl::IComponent> aidlComponent;
+ ::ndk::ScopedAStatus transStatus = mAidlBase->createComponent(
+ name,
+ aidlListener,
+ bufferpool2_aidl::implementation::ClientManager::getInstance(),
+ &aidlComponent);
+ c2_status_t status = GetC2Status(transStatus, "createComponent");
+ if (status != C2_OK) {
+ return status;
+ } else if (!aidlComponent) {
+ LOG(ERROR) << "createComponent(" << name.c_str()
+ << ") -- null component.";
+ return C2_CORRUPTED;
+ }
+ *component = std::make_shared<Codec2Client::Component>(aidlComponent);
+ status = (*component)->setDeathListener((*component), listener);
+ if (status != C2_OK) {
+ LOG(ERROR) << "createComponent(" << name.c_str()
+ << ") -- failed to set up death listener: "
+ << status << ".";
+ }
+ (*component)->mAidlBufferPoolSender->setReceiver(mAidlHostPoolManager);
+ aidlListener->component = *component;
+ return status;
+}
+
+c2_status_t Codec2Client::createComponent_hidl(
+ const C2String& name,
+ const std::shared_ptr<Codec2Client::Listener>& listener,
+ std::shared_ptr<Codec2Client::Component>* const component) {
c2_status_t status;
sp<Component::HidlListener> hidlListener = new Component::HidlListener{};
hidlListener->base = listener;
@@ -1593,6 +2411,13 @@
return a < b;
});
+ if (__builtin_available(android 36, *)) {
+ if (android::media::codec::provider_->in_process_sw_audio_codec_support()
+ && nullptr != ApexCodec_GetComponentStore()) {
+ names.push_back("__ApexCodecs__");
+ }
+ }
+
// Summarize to logcat.
if (names.empty()) {
LOG(INFO) << "No Codec2 services declared in the manifest.";
@@ -1649,7 +2474,13 @@
std::string const& name = GetServiceNames()[index];
LOG(VERBOSE) << "Creating a Codec2 client to service \"" << name << "\"";
- if (c2_aidl::utils::IsSelected()) {
+ if (name == "__ApexCodecs__") {
+ if (__builtin_available(android 36, *)) {
+ return std::make_shared<Codec2Client>(ApexCodec_GetComponentStore(), index);
+ } else {
+ LOG(FATAL) << "ApexCodecs not supported on Android version older than 36";
+ }
+ } else if (c2_aidl::utils::IsSelected()) {
if (__builtin_available(android __ANDROID_API_S__, *)) {
std::string instanceName =
::android::base::StringPrintf("%s/%s", AidlBase::descriptor, name.c_str());
@@ -2054,16 +2885,41 @@
mGraphicBufferAllocators{std::make_unique<GraphicBufferAllocators>()} {
}
+Codec2Client::Component::Component(ApexCodec_Component *base, const C2String &name)
+ : Configurable{[base]() -> ApexCodec_Configurable * {
+ if (__builtin_available(android 36, *)) {
+ return ApexCodec_Component_getConfigurable(base);
+ } else {
+ return nullptr;
+ }
+ }(), name},
+ mApexBase{base} {
+}
+
Codec2Client::Component::~Component() {
if (mAidlDeathSeq) {
GetAidlDeathManager()->unlinkToDeath(*mAidlDeathSeq, mAidlBase);
}
+ if (mApexBase) {
+ if (__builtin_available(android 36, *)) {
+ ApexCodec_Component_destroy(mApexBase);
+ }
+ mApexBase = nullptr;
+ }
}
c2_status_t Codec2Client::Component::createBlockPool(
C2Allocator::id_t id,
C2BlockPool::local_id_t* blockPoolId,
std::shared_ptr<Codec2Client::Configurable>* configurable) {
+ if (mApexBase) {
+ std::shared_ptr<C2BlockPool> blockPool;
+ CreateCodec2BlockPool(id, nullptr, &blockPool);
+ *blockPoolId = blockPool->getLocalId();
+ *configurable = nullptr;
+ mBlockPools[*blockPoolId] = blockPool;
+ return C2_OK;
+ }
if (mAidlBase) {
c2_aidl::IComponent::BlockPool aidlBlockPool;
c2_status_t status = C2_OK;
@@ -2134,6 +2990,10 @@
c2_status_t Codec2Client::Component::destroyBlockPool(
C2BlockPool::local_id_t localId) {
+ if (mApexBase) {
+ mBlockPools.erase(localId);
+ return C2_OK;
+ }
if (mAidlBase) {
mGraphicBufferAllocators->remove(localId);
::ndk::ScopedAStatus transStatus = mAidlBase->destroyBlockPool(localId);
@@ -2150,7 +3010,10 @@
void Codec2Client::Component::handleOnWorkDone(
const std::list<std::unique_ptr<C2Work>> &workItems) {
- if (mAidlBase) {
+ if (mApexBase) {
+ // no-op
+ return;
+ } else if (mAidlBase) {
holdIgbaBlocks(workItems);
} else {
// Output bufferqueue-based blocks' lifetime management
@@ -2160,6 +3023,10 @@
c2_status_t Codec2Client::Component::queue(
std::list<std::unique_ptr<C2Work>>* const items) {
+ if (mApexBase) {
+ mApexHandler->queue(*items);
+ return C2_OK;
+ }
if (mAidlBase) {
c2_aidl::WorkBundle workBundle;
if (!c2_aidl::utils::ToAidl(&workBundle, *items, mAidlBufferPoolSender.get())) {
@@ -2191,6 +3058,13 @@
C2Component::flush_mode_t mode,
std::list<std::unique_ptr<C2Work>>* const flushedWork) {
(void)mode; // Flush mode isn't supported in HIDL/AIDL yet.
+ if (mApexBase) {
+ if (__builtin_available(android 36, *)) {
+ return (c2_status_t)ApexCodec_Component_flush(mApexBase);
+ } else {
+ return C2_OMITTED;
+ }
+ }
c2_status_t status = C2_OK;
if (mAidlBase) {
c2_aidl::WorkBundle workBundle;
@@ -2250,6 +3124,9 @@
}
c2_status_t Codec2Client::Component::drain(C2Component::drain_mode_t mode) {
+ if (mApexBase) {
+ return C2_OMITTED;
+ }
if (mAidlBase) {
::ndk::ScopedAStatus transStatus = mAidlBase->drain(
mode == C2Component::DRAIN_COMPONENT_WITH_EOS);
@@ -2270,6 +3147,10 @@
}
c2_status_t Codec2Client::Component::start() {
+ if (mApexBase) {
+ // no-op
+ return C2_OK;
+ }
if (mAidlBase) {
::ndk::ScopedAStatus transStatus = mAidlBase->start();
return GetC2Status(transStatus, "start");
@@ -2306,6 +3187,13 @@
}
c2_status_t Codec2Client::Component::reset() {
+ if (mApexBase) {
+ if (__builtin_available(android 36, *)) {
+ return (c2_status_t)ApexCodec_Component_reset(mApexBase);
+ } else {
+ return C2_OMITTED;
+ }
+ }
if (mAidlBase) {
::ndk::ScopedAStatus transStatus = mAidlBase->reset();
return GetC2Status(transStatus, "reset");
@@ -2324,6 +3212,13 @@
}
c2_status_t Codec2Client::Component::release() {
+ if (mApexBase) {
+ if (__builtin_available(android 36, *)) {
+ return (c2_status_t)ApexCodec_Component_reset(mApexBase);
+ } else {
+ return C2_OMITTED;
+ }
+ }
if (mAidlBase) {
::ndk::ScopedAStatus transStatus = mAidlBase->release();
return GetC2Status(transStatus, "release");
@@ -2345,6 +3240,10 @@
uint32_t avSyncHwId,
native_handle_t** sidebandHandle) {
*sidebandHandle = nullptr;
+ if (mApexBase) {
+ // tunneling is not supported in APEX
+ return C2_OMITTED;
+ }
if (mAidlBase) {
::aidl::android::hardware::common::NativeHandle handle;
::ndk::ScopedAStatus transStatus = mAidlBase->configureVideoTunnel(avSyncHwId, &handle);
@@ -2616,6 +3515,10 @@
c2_status_t Codec2Client::Component::connectToInputSurface(
const std::shared_ptr<InputSurface>& inputSurface,
std::shared_ptr<InputSurfaceConnection>* connection) {
+ if (mApexBase) {
+ // FIXME
+ return C2_OMITTED;
+ }
if (mAidlBase) {
// FIXME
return C2_OMITTED;
@@ -2644,6 +3547,10 @@
const sp<HGraphicBufferProducer1>& producer,
const sp<HGraphicBufferSource>& source,
std::shared_ptr<InputSurfaceConnection>* connection) {
+ if (mApexBase) {
+ LOG(WARNING) << "Connecting to OMX input surface is not supported for AIDL C2 HAL";
+ return C2_OMITTED;
+ }
if (mAidlBase) {
LOG(WARNING) << "Connecting to OMX input surface is not supported for AIDL C2 HAL";
return C2_OMITTED;
@@ -2669,6 +3576,10 @@
}
c2_status_t Codec2Client::Component::disconnectFromInputSurface() {
+ if (mApexBase) {
+ // FIXME
+ return C2_OMITTED;
+ }
if (mAidlBase) {
// FIXME
return C2_OMITTED;
@@ -2693,6 +3604,16 @@
return sManager;
}
+c2_status_t Codec2Client::Component::initApexHandler(
+ const std::shared_ptr<Listener> &listener,
+ const std::shared_ptr<Component> &comp) {
+ if (!mApexBase) {
+ return C2_BAD_STATE;
+ }
+ mApexHandler = std::make_unique<ApexHandler>(mApexBase, listener, comp);
+ return C2_OK;
+}
+
c2_status_t Codec2Client::Component::setDeathListener(
const std::shared_ptr<Component>& component,
const std::shared_ptr<Listener>& listener) {
diff --git a/media/codec2/hal/client/include/codec2/hidl/client.h b/media/codec2/hal/client/include/codec2/hidl/client.h
index 7923f04..35c87e0 100644
--- a/media/codec2/hal/client/include/codec2/hidl/client.h
+++ b/media/codec2/hal/client/include/codec2/hidl/client.h
@@ -112,6 +112,10 @@
struct IGraphicBufferSource;
} // namespace android::hardware::media::omx::V1_0
+struct ApexCodec_ComponentStore;
+struct ApexCodec_Component;
+struct ApexCodec_Configurable;
+
namespace android {
// This class is supposed to be called Codec2Client::Configurable, but forward
@@ -148,6 +152,7 @@
explicit Codec2ConfigurableClient(const sp<HidlBase> &hidlBase);
explicit Codec2ConfigurableClient(const std::shared_ptr<AidlBase> &aidlBase);
+ Codec2ConfigurableClient(ApexCodec_Configurable *base, const C2String &name);
const C2String& getName() const;
@@ -172,6 +177,7 @@
private:
struct HidlImpl;
struct AidlImpl;
+ struct ApexImpl;
const std::unique_ptr<ImplBase> mImpl;
};
@@ -282,12 +288,16 @@
std::shared_ptr<AidlBase> const& base,
std::shared_ptr<Codec2ConfigurableClient::AidlBase> const& configurable,
size_t serviceIndex);
+ Codec2Client(
+ ApexCodec_ComponentStore* base,
+ size_t serviceIndex);
protected:
sp<HidlBase1_0> mHidlBase1_0;
sp<HidlBase1_1> mHidlBase1_1;
sp<HidlBase1_2> mHidlBase1_2;
std::shared_ptr<AidlBase> mAidlBase;
+ ApexCodec_ComponentStore* mApexBase{nullptr};
// Finds the first store where the predicate returns C2_OK and returns the
// last predicate result. The predicate will be tried on all stores. The
@@ -325,6 +335,20 @@
std::vector<C2Component::Traits> _listComponents(bool* success) const;
class Cache;
+
+private:
+ c2_status_t createComponent_aidl(
+ C2String const& name,
+ std::shared_ptr<Listener> const& listener,
+ std::shared_ptr<Component>* const component);
+ c2_status_t createComponent_hidl(
+ C2String const& name,
+ std::shared_ptr<Listener> const& listener,
+ std::shared_ptr<Component>* const component);
+ c2_status_t createComponent_apex(
+ C2String const& name,
+ std::shared_ptr<Listener> const& listener,
+ std::shared_ptr<Component>* const component);
};
struct Codec2Client::Interface : public Codec2Client::Configurable {
@@ -508,11 +532,16 @@
c2_status_t disconnectFromInputSurface();
+ c2_status_t initApexHandler(
+ const std::shared_ptr<Listener> &listener,
+ const std::shared_ptr<Component> &comp);
+
// base cannot be null.
Component(const sp<HidlBase>& base);
Component(const sp<HidlBase1_1>& base);
Component(const sp<HidlBase1_2>& base);
Component(const std::shared_ptr<AidlBase>& base);
+ Component(ApexCodec_Component* base, const C2String& name);
~Component();
@@ -521,12 +550,16 @@
sp<HidlBase1_1> mHidlBase1_1;
sp<HidlBase1_2> mHidlBase1_2;
std::shared_ptr<AidlBase> mAidlBase;
+ ApexCodec_Component *mApexBase{nullptr};
struct HidlBufferPoolSender;
struct AidlBufferPoolSender;
std::unique_ptr<HidlBufferPoolSender> mHidlBufferPoolSender;
std::unique_ptr<AidlBufferPoolSender> mAidlBufferPoolSender;
+ class ApexHandler;
+ std::unique_ptr<ApexHandler> mApexHandler;
+
struct OutputBufferQueue;
std::unique_ptr<OutputBufferQueue> mOutputBufferQueue;
@@ -547,6 +580,11 @@
const std::shared_ptr<Listener>& listener);
sp<::android::hardware::hidl_death_recipient> mDeathRecipient;
+ // This is a map of block pools created for APEX components in the client.
+ // Note that the APEX codec API requires output buffers to be passed from the client,
+ // so the client creates and keeps track of the block pools here.
+ std::map<C2BlockPool::local_id_t, std::shared_ptr<C2BlockPool>> mBlockPools;
+
friend struct Codec2Client;
struct HidlListener;
diff --git a/media/codec2/sfplugin/Codec2InfoBuilder.cpp b/media/codec2/sfplugin/Codec2InfoBuilder.cpp
index fd242a1..0f5cdd6 100644
--- a/media/codec2/sfplugin/Codec2InfoBuilder.cpp
+++ b/media/codec2/sfplugin/Codec2InfoBuilder.cpp
@@ -16,6 +16,9 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "Codec2InfoBuilder"
+
+#include <cstdlib>
+
#include <log/log.h>
#include <strings.h>
@@ -508,6 +511,10 @@
&& !hasPrefix(v.first, "domain-")
&& !hasPrefix(v.first, "variant-")) {
writer->addGlobalSetting(v.first.c_str(), v.second.c_str());
+ if (v.first == "max-concurrent-instances") {
+ MediaCodecInfoWriter::SetMaxSupportedInstances(
+ (int32_t)strtol(v.second.c_str(), NULL, 10));
+ }
}
}
@@ -797,6 +804,7 @@
}
}
}
+ codecInfo->createCodecCaps();
}
}
return OK;
diff --git a/media/janitors/better_together_OWNERS b/media/janitors/better_together_OWNERS
new file mode 100644
index 0000000..70723cb
--- /dev/null
+++ b/media/janitors/better_together_OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 137631
+
+aquilescanta@google.com
+asapperstein@google.com
+halliwell@google.com
diff --git a/media/libaaudio/fuzzer/libaaudio_fuzzer.cpp b/media/libaaudio/fuzzer/libaaudio_fuzzer.cpp
index c3b43ab..07fed18 100644
--- a/media/libaaudio/fuzzer/libaaudio_fuzzer.cpp
+++ b/media/libaaudio/fuzzer/libaaudio_fuzzer.cpp
@@ -25,6 +25,7 @@
constexpr int32_t kRandomStringLength = 256;
constexpr int32_t kMaxRuns = 100;
constexpr int64_t kNanosPerMillisecond = 1000 * 1000;
+constexpr int32_t kAAudioAttributesTagsMaxSize = 256;
constexpr aaudio_direction_t kDirections[] = {
AAUDIO_DIRECTION_OUTPUT, AAUDIO_DIRECTION_INPUT, AAUDIO_UNSPECIFIED};
@@ -185,10 +186,10 @@
AAudioStreamBuilder_setFramesPerDataCallback(mAaudioBuilder, framesPerDataCallback);
const size_t tagsNumBytes = fdp.ConsumeIntegralInRange<size_t>(
- 0, AAUDIO_ATTRIBUTES_TAGS_MAX_SIZE + 10);
- AAudioStreamBuilder_setTags(mAaudioBuilder,
- (tagsNumBytes == 0 ? nullptr
- : fdp.ConsumeBytesAsString(tagsNumBytes).c_str()));
+ 0, kAAudioAttributesTagsMaxSize + 10);
+ AAudioStreamBuilder_addTag(mAaudioBuilder,
+ (tagsNumBytes == 0 ? nullptr
+ : fdp.ConsumeBytesAsString(tagsNumBytes).c_str()));
aaudio_policy_t policy =
fdp.PickValueInArray({fdp.PickValueInArray(kPolicies), fdp.ConsumeIntegral<int32_t>()});
@@ -200,7 +201,7 @@
int32_t maxFrames = 0;
int32_t count = 0;
aaudio_stream_state_t state = AAUDIO_STREAM_STATE_UNKNOWN;
- char tags[AAUDIO_ATTRIBUTES_TAGS_MAX_SIZE + 1];
+ int numOfTags = 0;
invokeAAudioSetAPIs(fdp);
@@ -320,7 +321,9 @@
(void)AAudioStream_getBufferSizeInFrames(mAaudioStream);
},
[&]() {
- (void)AAudioStream_getTags(mAaudioStream, tags);
+ char** tags = nullptr;
+ (void)AAudioStream_obtainTags(mAaudioStream, &tags);
+ AAudioStream_releaseTags(mAaudioStream, tags);
},
[&]() {
(void)AAudioStream_isMMapUsed(mAaudioStream);
diff --git a/media/libaaudio/include/aaudio/AAudio.h b/media/libaaudio/include/aaudio/AAudio.h
index 136edcc..e72685c 100644
--- a/media/libaaudio/include/aaudio/AAudio.h
+++ b/media/libaaudio/include/aaudio/AAudio.h
@@ -119,8 +119,42 @@
*
* Available since API level 34.
*/
- AAUDIO_FORMAT_IEC61937
+ AAUDIO_FORMAT_IEC61937,
+ /**
+ * This format is used for audio compressed in MP3 format.
+ */
+ AAUDIO_FORMAT_MP3,
+
+ /**
+ * This format is used for audio compressed in AAC LC format.
+ */
+ AAUDIO_FORMAT_AAC_LC,
+
+ /**
+ * This format is used for audio compressed in AAC HE V1 format.
+ */
+ AAUDIO_FORMAT_AAC_HE_V1,
+
+ /**
+ * This format is used for audio compressed in AAC HE V2 format.
+ */
+ AAUDIO_FORMAT_AAC_HE_V2,
+
+ /**
+ * This format is used for audio compressed in AAC ELD format.
+ */
+ AAUDIO_FORMAT_AAC_ELD,
+
+ /**
+ * This format is used for audio compressed in AAC XHE format.
+ */
+ AAUDIO_FORMAT_AAC_XHE,
+
+ /**
+ * This format is used for audio compressed in OPUS.
+ */
+ AAUDIO_FORMAT_OPUS
};
typedef int32_t aaudio_format_t;
@@ -335,7 +369,23 @@
/**
* Reducing latency is more important than battery life.
*/
- AAUDIO_PERFORMANCE_MODE_LOW_LATENCY
+ AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
+
+ /**
+ * Extending battery life is more important than low latency.
+ *
+ * This mode is not supported in input streams.
+ * This mode will play through the offloaded audio path to save battery life.
+ *
+ * Comparing to mode {@link #AAUDIO_PERFORMANCE_MODE_POWER_SAVING}, the stream at
+ * this mode will be able to write a large amount(several seconds) of data within a
+ * short time. The written data will be queued in a hardware buffer. After that, the
+ * app can suspend its thread/process that playing audio, the audio framework's data
+ * pipe will be suspended automatically and the CPU will be allowed to sleep for
+ * power saving. When all queued data are played, the apps will be able to get callback
+ * to feed more data.
+ */
+ AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED
};
typedef int32_t aaudio_performance_mode_t;
@@ -845,6 +895,180 @@
};
typedef uint32_t aaudio_channel_mask_t;
+// The values are copied from JAVA SDK device types defined in android/media/AudioDeviceInfo.java
+// When a new value is added, it should be added here and handled by the conversion at
+// AAudioConvert_aaudioToAndroidDeviceType.
+typedef enum AAudio_DeviceType : int32_t {
+ /**
+ * A device type describing the attached earphone speaker.
+ */
+ AAUDIO_DEVICE_BUILTIN_EARPIECE = 1,
+
+ /**
+ * A device type describing the speaker system (i.e. a mono speaker or stereo speakers) built
+ * in a device.
+ */
+ AAUDIO_DEVICE_BUILTIN_SPEAKER = 2,
+
+ /**
+ * A device type describing a headset, which is the combination of a headphones and microphone.
+ */
+ AAUDIO_DEVICE_WIRED_HEADSET = 3,
+
+ /**
+ * A device type describing a pair of wired headphones.
+ */
+ AAUDIO_DEVICE_WIRED_HEADPHONES = 4,
+
+ /**
+ * A device type describing an analog line-level connection.
+ */
+ AAUDIO_DEVICE_LINE_ANALOG = 5,
+
+ /**
+ * A device type describing a digital line connection (e.g. SPDIF).
+ */
+ AAUDIO_DEVICE_LINE_DIGITAL = 6,
+
+ /**
+ * A device type describing a Bluetooth device typically used for telephony.
+ */
+ AAUDIO_DEVICE_BLUETOOTH_SCO = 7,
+
+ /**
+ * A device type describing a Bluetooth device supporting the A2DP profile.
+ */
+ AAUDIO_DEVICE_BLUETOOTH_A2DP = 8,
+
+ /**
+ * A device type describing an HDMI connection .
+ */
+ AAUDIO_DEVICE_HDMI = 9,
+
+ /**
+ * A device type describing the Audio Return Channel of an HDMI connection.
+ */
+ AAUDIO_DEVICE_HDMI_ARC = 10,
+
+ /**
+ * A device type describing a USB audio device.
+ */
+ AAUDIO_DEVICE_USB_DEVICE = 11,
+
+ /**
+ * A device type describing a USB audio device in accessory mode.
+ */
+ AAUDIO_DEVICE_USB_ACCESSORY = 12,
+
+ /**
+ * A device type describing the audio device associated with a dock.
+ * Starting at API 34, this device type only represents digital docks, while docks with an
+ * analog connection are represented with {@link #AAUDIO_DEVICE_DOCK_ANALOG}.
+ */
+ AAUDIO_DEVICE_DOCK = 13,
+
+ /**
+ * A device type associated with the transmission of audio signals over FM.
+ */
+ AAUDIO_DEVICE_FM = 14,
+
+ /**
+ * A device type describing the microphone(s) built in a device.
+ */
+ AAUDIO_DEVICE_BUILTIN_MIC = 15,
+
+ /**
+ * A device type for accessing the audio content transmitted over FM.
+ */
+ AAUDIO_DEVICE_FM_TUNER = 16,
+
+ /**
+ * A device type for accessing the audio content transmitted over the TV tuner system.
+ */
+ AAUDIO_DEVICE_TV_TUNER = 17,
+
+ /**
+ * A device type describing the transmission of audio signals over the telephony network.
+ */
+ AAUDIO_DEVICE_TELEPHONY = 18,
+
+ /**
+ * A device type describing the auxiliary line-level connectors.
+ */
+ AAUDIO_DEVICE_AUX_LINE = 19,
+
+ /**
+ * A device type connected over IP.
+ */
+ AAUDIO_DEVICE_IP = 20,
+
+ /**
+ * A type-agnostic device used for communication with external audio systems.
+ */
+ AAUDIO_DEVICE_BUS = 21,
+
+ /**
+ * A device type describing a USB audio headset.
+ */
+ AAUDIO_DEVICE_USB_HEADSET = 22,
+
+ /**
+ * A device type describing a Hearing Aid.
+ */
+ AAUDIO_DEVICE_HEARING_AID = 23,
+
+ /**
+ * A device type describing the speaker system (i.e. a mono speaker or stereo speakers) built
+ * in a device, that is specifically tuned for outputting sounds like notifications and alarms
+ * (i.e. sounds the user couldn't necessarily anticipate).
+ * <p>Note that this physical audio device may be the same as {@link #TYPE_BUILTIN_SPEAKER}
+ * but is driven differently to safely accommodate the different use case.</p>
+ */
+ AAUDIO_DEVICE_BUILTIN_SPEAKER_SAFE = 24,
+
+ /**
+ * A device type for rerouting audio within the Android framework between mixes and
+ * system applications.
+ */
+ AAUDIO_DEVICE_REMOTE_SUBMIX = 25,
+ /**
+ * A device type describing a Bluetooth Low Energy (BLE) audio headset or headphones.
+ * Headphones are grouped with headsets when the device is a sink:
+ * the features of headsets and headphones with regard to playback are the same.
+ */
+ AAUDIO_DEVICE_BLE_HEADSET = 26,
+
+ /**
+ * A device type describing a Bluetooth Low Energy (BLE) audio speaker.
+ */
+ AAUDIO_DEVICE_BLE_SPEAKER = 27,
+
+ /**
+ * A device type describing an Echo Canceller loopback Reference.
+ * This device is only used when capturing with MediaRecorder.AudioSource.ECHO_REFERENCE,
+ * which requires privileged permission
+ * {@link android.Manifest.permission#CAPTURE_AUDIO_OUTPUT}.
+ *
+ * Note that this is not exposed as it is a system API that requires privileged permission.
+ */
+ // AAUDIO_DEVICE_ECHO_REFERENCE = 28,
+
+ /**
+ * A device type describing the Enhanced Audio Return Channel of an HDMI connection.
+ */
+ AAUDIO_DEVICE_HDMI_EARC = 29,
+
+ /**
+ * A device type describing a Bluetooth Low Energy (BLE) broadcast group.
+ */
+ AAUDIO_DEVICE_BLE_BROADCAST = 30,
+
+ /**
+ * A device type describing the audio device associated with a dock using an analog connection.
+ */
+ AAUDIO_DEVICE_DOCK_ANALOG = 31
+} AAudio_DeviceType;
+
typedef struct AAudioStreamStruct AAudioStream;
typedef struct AAudioStreamBuilderStruct AAudioStreamBuilder;
@@ -1090,7 +1314,8 @@
* Set the requested performance mode.
*
* Supported modes are {@link #AAUDIO_PERFORMANCE_MODE_NONE},
- * {@link #AAUDIO_PERFORMANCE_MODE_POWER_SAVING} * and {@link #AAUDIO_PERFORMANCE_MODE_LOW_LATENCY}.
+ * {@link #AAUDIO_PERFORMANCE_MODE_POWER_SAVING}, {@link #AAUDIO_PERFORMANCE_MODE_LOW_LATENCY} and
+ * {@link #AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED}.
*
* The default, if you do not call this function, is {@link #AAUDIO_PERFORMANCE_MODE_NONE}.
*
@@ -1475,6 +1700,44 @@
__INTRODUCED_IN(26);
/**
+ * Prototype for the callback function that is passed to
+ * AAudioStreamBuilder_setPresentationEndCallback().
+ *
+ * This will be called when all the buffers of an offloaded stream that were queued in the audio
+ * system (e.g. the combination of the Android audio framework and the device's audio hardware)
+ * have been played after AudioStream_requestStop() has been called.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream(), which must be an
+ * output stream as the offloaded mode is only supported for output stream
+ * @param userData the same address that was passed to
+ * AAudioStreamBuilder_setPresentationEndCallback().
+ */
+typedef void (*AAudioStream_presentationEndCallback)(AAudioStream* _Nonnull stream,
+ void* _Null_unspecified userData);
+
+/**
+ * Request that AAudio call this function when all the buffers of an offloaded stream that were
+ * queued in the audio system (e.g. the combination of the Android audio framework and the device's
+ * audio hardware) have been played.
+ *
+ * The presentation end callback must be used together with the data callback.
+ * The presentation edn callback won't be called if the stream is closed before all the data
+ * is played.
+ *
+ * Available since API level 36.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder()
+ * @param callback pointer to a function that will be called when all the buffers of an offloaded
+ * stream that were queued have been played.
+ * @param userData pointer to an application data structure that will be passed
+ * to the callback functions.
+ */
+AAUDIO_API void AAudioStreamBuilder_setPresentationEndCallback(
+ AAudioStreamBuilder* _Nonnull builder,
+ AAudioStream_presentationEndCallback _Nonnull callback,
+ void* _Nullable userData) __INTRODUCED_IN(36);
+
+/**
* Open a stream based on the options in the StreamBuilder.
*
* AAudioStream_close() must be called when finished with the stream to recover
@@ -1909,18 +2172,17 @@
* Available since API level 26.
*
* @param stream reference provided by AAudioStreamBuilder_openStream()
- * @return actual device id. If there are multiple device ids used, the first device picked by
- * the audio policy engine will be returned.
+ * @return actual device id. If there are multiple device ids used,
+ * this will return the first device id from AAudioStream_getDeviceIds().
*/
AAUDIO_API int32_t AAudioStream_getDeviceId(AAudioStream* _Nonnull stream) __INTRODUCED_IN(26);
/**
- * Available since API level 36.
- *
* Call this function after AAudioStreamBuilder_openStream().
- * This function will crash if stream is null.
* An array of size 16 should generally be large enough to fit all device identifiers.
*
+ * Available since API level 36.
+ *
* @param stream reference provided by AAudioStreamBuilder_openStream().
* @param ids reference to an array of ids.
* @params numIds size allocated to the array of ids.
@@ -1933,7 +2195,7 @@
* Otherwise, if ids is null, return {@link #AAUDIO_ERROR_ILLEGAL_ARGUMENT}.
*/
AAUDIO_API aaudio_result_t AAudioStream_getDeviceIds(AAudioStream* _Nonnull stream,
- int32_t* _Nonnull ids, int32_t* _Nonnull numIds) __INTRODUCED_IN(36);
+ int32_t* _Nullable ids, int32_t* _Nullable numIds) __INTRODUCED_IN(36);
/**
* Available since API level 26.
@@ -2188,6 +2450,155 @@
AAUDIO_API aaudio_channel_mask_t AAudioStream_getChannelMask(AAudioStream* _Nonnull stream)
__INTRODUCED_IN(32);
+/**
+ * Configures the delay and padding values for the current stream playing in offload mode.
+ * This should only be used on a stream whose performance mode is
+ * {@link #AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED} and the format is compressed format.
+ * The unit is frames, where a frame includes samples for all audio channels, e.g. 100 frames
+ * for a stereo stream corresponds to 200 interleaved PCM samples.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @param delayInFrames number of frames to be ignored at the beginning of the stream. A value
+ * of 0 indicates no delay is to be applied.
+ * @param paddingInFrames number of frames to be ignored at the end of the stream. A value of 0
+ * of 0 indicates no padding is to be applied.
+ * @return {@link #AAUDIO_OK} if the delay and padding values are set successfully,
+ * or {@link #AAUDIO_ERROR_ILLEGAL_ARGUMENT} if delayInFrames or paddingInFrames
+ * is less than 0,
+ * or {@link #AAUDIO_ERROR_UNIMPLEMENTED} if the stream is not an output stream whose
+ * performance mode is {@link #AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED},
+ * or {@link #AAUDIO_ERROR_INVALID_STATE} if the stream is not yet initialized.
+ */
+AAUDIO_API aaudio_result_t AAudioStream_setOffloadDelayPadding(
+ AAudioStream* _Nonnull stream, int32_t delayInFrames, int32_t paddingInFrames)
+ __INTRODUCED_IN(36);
+
+/**
+ * Return the decoder delay of an offloaded stream in frames.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return the offload delay in frames that previously set with
+ * {@link #AAudioStream_setOffloadDelayPadding},
+ * or 0 if it was never modified,
+ * or {@link #AAUDIO_ERROR_UNIMPLEMENTED} if the stream is not an output stream whose
+ * performance mode is {@link #AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED},
+ * or {@link #AAUDIO_ERROR_INVALID_STATE} if the stream is not yet initialized.
+ */
+AAUDIO_API int32_t AAudioStream_getOffloadDelay(AAudioStream* _Nonnull stream) __INTRODUCED_IN(36);
+
+/**
+ * Return the decoder padding of an offloaded stream in frames.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return the offload padding in frames that previously set with
+ * {@link #AAudioStream_setOffloadDelayPadding},
+ * or 0 if it was never modified,
+ * or {@link #AAUDIO_ERROR_UNIMPLEMENTED} if the stream is not an output stream whose
+ * performance mode is {@link #AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED},
+ * or {@link #AAUDIO_ERROR_INVALID_STATE} if the stream is not yet initialized.
+ */
+AAUDIO_API int32_t AAudioStream_getOffloadPadding(AAudioStream* _Nonnull stream)
+ __INTRODUCED_IN(36);
+
+/**
+ * Declares that the last data writing operation on this stream provided the last buffer of this
+ * stream.
+ * After the end of stream, previously set padding and delay values are ignored. That indicates
+ * all written data will be played.
+ * Use this method in the same thread as any data writing operation.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return {@link #AAUDIO_OK} on success,
+ * or {@link #AAUDIO_ERROR_UNIMPLEMENTED} if the stream is not an output stream whose
+ * performance mode is {@link #AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED},
+ * or {@link #AAUDIO_ERROR_INVALID_STATE} if the stream is not yet initialized.
+ */
+AAUDIO_API aaudio_result_t AAudioStream_setOffloadEndOfStream(AAudioStream* _Nonnull stream)
+ __INTRODUCED_IN(36);
+
+/************************************************************************************
+ * Helper functions for AAudio MMAP.
+ * AAudio MMAP data path uses a memory region that is shared between the hardware and
+ * the audio software. The shared memory is referenced using a file descriptor that is
+ * generated by the ALSA driver. Apps can read/write directly from/to the shared
+ * memory, which helps improve the audio latency.
+ ************************************************************************************/
+
+/**
+ * When the audio is played/recorded via AAudio MMAP data path, the apps can write to/read from
+ * a shared memory that will also be accessed directly by hardware. That reduces the audio latency.
+ * The following values are used to describe how AAudio MMAP is supported.
+ */
+enum {
+ /**
+ * AAudio MMAP is disabled and never used.
+ */
+ AAUDIO_POLICY_NEVER = 1,
+
+ /**
+ * AAudio MMAP support depends on device's availability. It will be used
+ * when it is possible or fallback to the normal path, where the audio data
+ * will be delivered via audio framework data pipeline.
+ */
+ AAUDIO_POLICY_AUTO,
+
+ /**
+ * AAudio MMAP must be used or fail.
+ */
+ AAUDIO_POLICY_ALWAYS
+};
+typedef int32_t aaudio_policy_t;
+
+/**
+ * Query how aaudio mmap is supported for the given device type.
+ *
+ * @param device device type
+ * @param direction {@link AAUDIO_DIRECTION_OUTPUT} or {@link AAUDIO_DIRECTION_INPUT}
+ * @return the mmap policy or {@link #AAUDIO_ERROR_ILLEGAL_ARGUMENT} if the device or direction
+ * is invalid or {@link #AAUDIO_ERROR_INTERNAL} if the audio HAL returns error.
+ */
+AAUDIO_API aaudio_policy_t AAudio_getPlatformMMapPolicy(
+ AAudio_DeviceType device, aaudio_direction_t direction) __INTRODUCED_IN(36);
+
+/**
+ * Query how aaudio exclusive mmap is supported for the given device type.
+ *
+ * @param device device type
+ * @param direction {@link AAUDIO_DIRECTION_OUTPUT} or {@link AAUDIO_DIRECTION_INPUT}
+ * @return the mmap exclusive policy or or {@link #AAUDIO_ERROR_ILLEGAL_ARGUMENT} if the device
+ * or direction is invalid or {@link #AAUDIO_ERROR_INTERNAL} if the audio HAL returns error.
+ */
+AAUDIO_API aaudio_policy_t AAudio_getPlatformMMapExclusivePolicy(
+ AAudio_DeviceType device, aaudio_direction_t direction) __INTRODUCED_IN(36);
+
+/**
+ * Control whether AAudioStreamBuilder_openStream() will use the new MMAP data path
+ * or the older "Legacy" data path.
+ *
+ * This will only affect the current process.
+ *
+ * If unspecified then the policy will be based on system properties or configuration.
+ *
+ * @param policy {@link #AAUDIO_UNSPECIFIED}, {@link #AAUDIO_POLICY_NEVER},
+ * {@link #AAUDIO_POLICY_AUTO}, or {@link #AAUDIO_POLICY_ALWAYS}
+ * @return AAUDIO_OK or a negative error
+ */
+AAUDIO_API aaudio_result_t AAudio_setMMapPolicy(aaudio_policy_t policy) __INTRODUCED_IN(36);
+
+/**
+ * Get the current MMAP policy set by AAudio_setMMapPolicy().
+ *
+ * @return current policy or {@link #AAUDIO_UNSPECIFIED} if it is never set.
+ */
+AAUDIO_API aaudio_policy_t AAudio_getMMapPolicy() __INTRODUCED_IN(36);
+
+/**
+ * Return true if the stream uses the MMAP data path versus the legacy path.
+ *
+ * @return true if the stream uses the MMAP data path
+ */
+AAUDIO_API bool AAudioStream_isMMapUsed(AAudioStream* _Nonnull stream) __INTRODUCED_IN(36);
+
#ifdef __cplusplus
}
#endif
diff --git a/media/libaaudio/include/aaudio/AAudioTesting.h b/media/libaaudio/include/aaudio/AAudioTesting.h
index 16d6c33..842a2db 100644
--- a/media/libaaudio/include/aaudio/AAudioTesting.h
+++ b/media/libaaudio/include/aaudio/AAudioTesting.h
@@ -22,274 +22,10 @@
#include <aaudio/AAudio.h>
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/************************************************************************************
- * The definitions below are only for testing. Do not use them in an application.
- * They may change or be removed at any time.
+ * These MMap functions were moved to AAudio.h
************************************************************************************/
-/**
- * When the audio is played/recorded via AAudio MMAP data path, the apps can write to/read from
- * a shared memory that will also be accessed directly by hardware. That reduces the audio latency.
- * The following values are used to describe how AAudio MMAP is supported.
- */
-enum {
- /**
- * AAudio MMAP is disabled and never used.
- */
- AAUDIO_POLICY_NEVER = 1,
-
- /**
- * AAudio MMAP support depends on device's availability. It will be used
- * when it is possible or fallback to the normal path, where the audio data
- * will be delivered via audio framework data pipeline.
- */
- AAUDIO_POLICY_AUTO,
-
- /**
- * AAudio MMAP must be used or fail.
- */
- AAUDIO_POLICY_ALWAYS
-};
-typedef int32_t aaudio_policy_t;
-
-// The values are copied from JAVA SDK device types defined in android/media/AudioDeviceInfo.java
-// When a new value is added, it should be added here and handled by the conversion at
-// AAudioConvert_aaudioToAndroidDeviceType.
-typedef enum AAudio_DeviceType : int32_t {
- /**
- * A device type describing the attached earphone speaker.
- */
- AAUDIO_DEVICE_BUILTIN_EARPIECE = 1,
-
- /**
- * A device type describing the speaker system (i.e. a mono speaker or stereo speakers) built
- * in a device.
- */
- AAUDIO_DEVICE_BUILTIN_SPEAKER = 2,
-
- /**
- * A device type describing a headset, which is the combination of a headphones and microphone.
- */
- AAUDIO_DEVICE_WIRED_HEADSET = 3,
-
- /**
- * A device type describing a pair of wired headphones.
- */
- AAUDIO_DEVICE_WIRED_HEADPHONES = 4,
-
- /**
- * A device type describing an analog line-level connection.
- */
- AAUDIO_DEVICE_LINE_ANALOG = 5,
-
- /**
- * A device type describing a digital line connection (e.g. SPDIF).
- */
- AAUDIO_DEVICE_LINE_DIGITAL = 6,
-
- /**
- * A device type describing a Bluetooth device typically used for telephony.
- */
- AAUDIO_DEVICE_BLUETOOTH_SCO = 7,
-
- /**
- * A device type describing a Bluetooth device supporting the A2DP profile.
- */
- AAUDIO_DEVICE_BLUETOOTH_A2DP = 8,
-
- /**
- * A device type describing an HDMI connection .
- */
- AAUDIO_DEVICE_HDMI = 9,
-
- /**
- * A device type describing the Audio Return Channel of an HDMI connection.
- */
- AAUDIO_DEVICE_HDMI_ARC = 10,
-
- /**
- * A device type describing a USB audio device.
- */
- AAUDIO_DEVICE_USB_DEVICE = 11,
-
- /**
- * A device type describing a USB audio device in accessory mode.
- */
- AAUDIO_DEVICE_USB_ACCESSORY = 12,
-
- /**
- * A device type describing the audio device associated with a dock.
- * Starting at API 34, this device type only represents digital docks, while docks with an
- * analog connection are represented with {@link #AAUDIO_DEVICE_DOCK_ANALOG}.
- */
- AAUDIO_DEVICE_DOCK = 13,
-
- /**
- * A device type associated with the transmission of audio signals over FM.
- */
- AAUDIO_DEVICE_FM = 14,
-
- /**
- * A device type describing the microphone(s) built in a device.
- */
- AAUDIO_DEVICE_BUILTIN_MIC = 15,
-
- /**
- * A device type for accessing the audio content transmitted over FM.
- */
- AAUDIO_DEVICE_FM_TUNER = 16,
-
- /**
- * A device type for accessing the audio content transmitted over the TV tuner system.
- */
- AAUDIO_DEVICE_TV_TUNER = 17,
-
- /**
- * A device type describing the transmission of audio signals over the telephony network.
- */
- AAUDIO_DEVICE_TELEPHONY = 18,
-
- /**
- * A device type describing the auxiliary line-level connectors.
- */
- AAUDIO_DEVICE_AUX_LINE = 19,
-
- /**
- * A device type connected over IP.
- */
- AAUDIO_DEVICE_IP = 20,
-
- /**
- * A type-agnostic device used for communication with external audio systems.
- */
- AAUDIO_DEVICE_BUS = 21,
-
- /**
- * A device type describing a USB audio headset.
- */
- AAUDIO_DEVICE_USB_HEADSET = 22,
-
- /**
- * A device type describing a Hearing Aid.
- */
- AAUDIO_DEVICE_HEARING_AID = 23,
-
- /**
- * A device type describing the speaker system (i.e. a mono speaker or stereo speakers) built
- * in a device, that is specifically tuned for outputting sounds like notifications and alarms
- * (i.e. sounds the user couldn't necessarily anticipate).
- * <p>Note that this physical audio device may be the same as {@link #TYPE_BUILTIN_SPEAKER}
- * but is driven differently to safely accommodate the different use case.</p>
- */
- AAUDIO_DEVICE_BUILTIN_SPEAKER_SAFE = 24,
-
- /**
- * A device type for rerouting audio within the Android framework between mixes and
- * system applications.
- */
- AAUDIO_DEVICE_REMOTE_SUBMIX = 25,
- /**
- * A device type describing a Bluetooth Low Energy (BLE) audio headset or headphones.
- * Headphones are grouped with headsets when the device is a sink:
- * the features of headsets and headphones with regard to playback are the same.
- */
- AAUDIO_DEVICE_BLE_HEADSET = 26,
-
- /**
- * A device type describing a Bluetooth Low Energy (BLE) audio speaker.
- */
- AAUDIO_DEVICE_BLE_SPEAKER = 27,
-
- /**
- * A device type describing an Echo Canceller loopback Reference.
- * This device is only used when capturing with MediaRecorder.AudioSource.ECHO_REFERENCE,
- * which requires privileged permission
- * {@link android.Manifest.permission#CAPTURE_AUDIO_OUTPUT}.
- *
- * Note that this is not exposed as it is a system API that requires privileged permission.
- */
- // AAUDIO_DEVICE_ECHO_REFERENCE = 28,
-
- /**
- * A device type describing the Enhanced Audio Return Channel of an HDMI connection.
- */
- AAUDIO_DEVICE_HDMI_EARC = 29,
-
- /**
- * A device type describing a Bluetooth Low Energy (BLE) broadcast group.
- */
- AAUDIO_DEVICE_BLE_BROADCAST = 30,
-
- /**
- * A device type describing the audio device associated with a dock using an analog connection.
- */
- AAUDIO_DEVICE_DOCK_ANALOG = 31
-} AAudio_DeviceType;
-
-/**
- * Query how aaudio mmap is supported for the given device type.
- *
- * @param device device type
- * @param direction {@link AAUDIO_DIRECTION_OUTPUT} or {@link AAUDIO_DIRECTION_INPUT}
- * @return the mmap policy or negative error
- */
-AAUDIO_API aaudio_policy_t AAudio_getPlatformMMapPolicy(
- AAudio_DeviceType device, aaudio_direction_t direction) __INTRODUCED_IN(36);
-
-/**
- * Query how aaudio exclusive mmap is supported for the given device type.
- *
- * @param device device type
- * @param direction {@link AAUDIO_DIRECTION_OUTPUT} or {@link AAUDIO_DIRECTION_INPUT}
- * @return the mmap exclusive policy or negative error
- */
-AAUDIO_API aaudio_policy_t AAudio_getPlatformMMapExclusivePolicy(
- AAudio_DeviceType device, aaudio_direction_t direction) __INTRODUCED_IN(36);
-
-/**
- * Control whether AAudioStreamBuilder_openStream() will use the new MMAP data path
- * or the older "Legacy" data path.
- *
- * This will only affect the current process.
- *
- * If unspecified then the policy will be based on system properties or configuration.
- *
- * @note This is only for testing. Do not use this in an application.
- * It may change or be removed at any time.
- *
- * @param policy AAUDIO_UNSPECIFIED, AAUDIO_POLICY_NEVER, AAUDIO_POLICY_AUTO, or AAUDIO_POLICY_ALWAYS
- * @return AAUDIO_OK or a negative error
- */
-AAUDIO_API aaudio_result_t AAudio_setMMapPolicy(aaudio_policy_t policy);
-
-/**
- * Get the current MMAP policy set by AAudio_setMMapPolicy().
- *
- * @note This is only for testing. Do not use this in an application.
- * It may change or be removed at any time.
- *
- * @return current policy
- */
-AAUDIO_API aaudio_policy_t AAudio_getMMapPolicy();
-
-/**
- * Return true if the stream uses the MMAP data path versus the legacy path.
- *
- * @note This is only for testing. Do not use this in an application.
- * It may change or be removed at any time.
- *
- * @return true if the stream uses the MMAP data path
- */
-AAUDIO_API bool AAudioStream_isMMapUsed(AAudioStream* stream);
-
-#ifdef __cplusplus
-}
-#endif
-
#endif //AAUDIO_AAUDIO_TESTING_H
/** @} */
diff --git a/media/libaaudio/include/system/aaudio/AAudio.h b/media/libaaudio/include/system/aaudio/AAudio.h
index 933ad35..4c2d291 100644
--- a/media/libaaudio/include/system/aaudio/AAudio.h
+++ b/media/libaaudio/include/system/aaudio/AAudio.h
@@ -27,51 +27,62 @@
#endif
/**
- * The tags string attributes allows OEMs to extend the
- * <a href="/reference/android/media/AudioAttributes">AudioAttributes</a>.
+ * Add one vendor extension tag that the output stream will carry.
*
- * Note that the maximum length includes all tags combined with delimiters and null terminator.
+ * The total size of all added tags, plus one for each tag terminator, must not be greater than
+ * <a href="/reference/android/system/media/audio">AUDIO_ATTRIBUTES_TAGS_MAX_SIZE</a>.
*
- * Note that it matches the equivalent value in
- * <a href="/reference/android/system/media/audio">AUDIO_ATTRIBUTES_TAGS_MAX_SIZE</a>
- * in the Android native API.
- */
-#define AAUDIO_ATTRIBUTES_TAGS_MAX_SIZE 256
-
-/**
- * Set one or more vendor extension tags that the output stream will carry.
- *
- * The tags can be used by the audio policy engine for routing purpose.
+ * The tag can be used by the audio policy engine for routing purpose.
* Routing is based on audio attributes, translated into legacy stream type.
* The stream types cannot be extended, so the product strategies have been introduced to allow
* vendor extension of routing capabilities.
* This could, for example, affect how volume and routing is handled for the stream.
*
- * The tags can also be used by a System App to pass vendor specific information through the
+ * The tag can also be used by a System App to pass vendor specific information through the
* framework to the HAL. That info could affect routing, ducking or other audio behavior in the HAL.
*
* By default, audio attributes tags are empty if this method is not called.
*
+ * When opening a stream with audio attributes tags, the client should hold
+ * MODIFY_AUDIO_SETTINGS_PRIVILEGED permission. Otherwise, the stream will fail to open.
+ *
* @param builder reference provided by AAudio_createStreamBuilder()
- * @param tags the desired tags to add, which must be UTF-8 format and null-terminated. The size
- * of the tags must be at most {@link #AAUDIO_ATTRIBUTES_TAGS_MAX_SIZE}. Multiple tags
- * must be separated by semicolons.
+ * @param tag the desired tag to add, which must be UTF-8 format and null-terminated.
* @return {@link #AAUDIO_OK} on success or {@link #AAUDIO_ERROR_ILLEGAL_ARGUMENT} if the given
- * tags is null or its length is greater than {@link #AAUDIO_ATTRIBUTES_TAGS_MAX_SIZE}.
+ * tags is null or {@link #AAUDIO_ERROR_OUT_OF_RANGE} if there is not room for more tags.
*/
-aaudio_result_t AAudioStreamBuilder_setTags(AAudioStreamBuilder* _Nonnull builder,
- const char* _Nonnull tags);
+aaudio_result_t AAudioStreamBuilder_addTag(AAudioStreamBuilder* _Nonnull builder,
+ const char* _Nonnull tag);
/**
- * Read the audio attributes' tags for the stream into a buffer.
- * The caller is responsible for allocating and freeing the returned data.
+ * Clear all the tags that has been added from calling
+ * {@link #AAudioStreamBuilder_addTag}.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder()
+ */
+void AAudioStreamBuilder_clearTags(AAudioStreamBuilder* _Nonnull builder);
+
+/**
+ * Allocate and read the audio attributes' tags for the stream into a buffer.
+ * The client is responsible to free the memory for tags by calling
+ * {@link #AAudioStream_releaseTags} unless the number of tags is 0.
*
* @param stream reference provided by AAudioStreamBuilder_openStream()
- * @param tags pointer to write the value to in UTF-8 that containing OEM extension tags. It must
- * be sized with {@link #AAUDIO_ATTRIBUTES_TAGS_MAX_SIZE}.
- * @return {@link #AAUDIO_OK} or {@link #AAUDIO_ERROR_ILLEGAL_ARGUMENT} if the given tags is null.
+ * @param tags a pointer to a variable that will be set to a pointer to an array of char* pointers
+ * @return number of tags or
+ * {@link #AAUDIO_ERROR_NO_MEMORY} if it fails to allocate memory for tags.
*/
-aaudio_result_t AAudioStream_getTags(AAudioStream* _Nonnull stream, char* _Nonnull tags);
+int32_t AAudioStream_obtainTags(AAudioStream* _Nonnull stream,
+ char* _Nullable* _Nullable* _Nonnull tags);
+
+/**
+ * Free the memory containing the tags that is allocated when calling
+ * {@link #AAudioStream_obtainTags}.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @param tags reference provided by AAudioStream_obtainTags()
+ */
+void AAudioStream_releaseTags(AAudioStream* _Nonnull stream, char* _Nonnull * _Nullable tags);
#ifdef __cplusplus
}
diff --git a/media/libaaudio/src/Android.bp b/media/libaaudio/src/Android.bp
index cccb096..0758170 100644
--- a/media/libaaudio/src/Android.bp
+++ b/media/libaaudio/src/Android.bp
@@ -169,6 +169,7 @@
"libaudioclient_aidl_conversion",
"libaudiofoundation",
"libaudioutils",
+ "libbase",
"libbinder",
"libcutils",
"liblog",
diff --git a/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp b/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
index 37c1a98..4e96219 100644
--- a/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
+++ b/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
@@ -59,7 +59,7 @@
setUsage(parcelable.usage);
static_assert(sizeof(aaudio_content_type_t) == sizeof(parcelable.contentType));
setContentType(parcelable.contentType);
- setTags(parcelable.tags);
+ setTags(std::set(parcelable.tags.begin(), parcelable.tags.end()));
static_assert(sizeof(aaudio_spatialization_behavior_t) ==
sizeof(parcelable.spatializationBehavior));
setSpatializationBehavior(parcelable.spatializationBehavior);
@@ -123,8 +123,8 @@
result.usage = getUsage();
static_assert(sizeof(aaudio_content_type_t) == sizeof(result.contentType));
result.contentType = getContentType();
- std::optional<std::string> tags = getTags();
- result.tags = tags.has_value() ? tags.value() : "";
+ auto tags = getTags();
+ result.tags = std::vector(tags.begin(), tags.end());
static_assert(
sizeof(aaudio_spatialization_behavior_t) == sizeof(result.spatializationBehavior));
result.spatializationBehavior = getSpatializationBehavior();
diff --git a/media/libaaudio/src/binding/aidl/aaudio/StreamParameters.aidl b/media/libaaudio/src/binding/aidl/aaudio/StreamParameters.aidl
index 7d7abce..88ad449 100644
--- a/media/libaaudio/src/binding/aidl/aaudio/StreamParameters.aidl
+++ b/media/libaaudio/src/binding/aidl/aaudio/StreamParameters.aidl
@@ -27,7 +27,7 @@
int /* aaudio_direction_t */ direction; // = AAUDIO_DIRECTION_OUTPUT;
int /* aaudio_usage_t */ usage; // = AAUDIO_UNSPECIFIED;
int /* aaudio_content_type_t */ contentType; // = AAUDIO_UNSPECIFIED;
- @utf8InCpp String tags; /* UTF8 */
+ @utf8InCpp String[] tags; /* UTF8 */
int /* aaudio_spatialization_behavior_t */spatializationBehavior; //= AAUDIO_UNSPECIFIED;
boolean isContentSpatialized; // = false;
int /* aaudio_input_preset_t */ inputPreset; // = AAUDIO_UNSPECIFIED;
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 6bc7dc2..33f152c 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -42,7 +42,6 @@
#include "fifo/FifoBuffer.h"
#include "utility/AudioClock.h"
#include <media/AidlConversion.h>
-#include <com_android_media_aaudio.h>
#include "AudioStreamInternal.h"
@@ -197,15 +196,6 @@
setSampleRate(configurationOutput.getSampleRate());
}
- if (!com::android::media::aaudio::sample_rate_conversion()) {
- if (getSampleRate() != getDeviceSampleRate()) {
- ALOGD("%s - skipping sample rate converter. SR = %d, Device SR = %d", __func__,
- getSampleRate(), getDeviceSampleRate());
- result = AAUDIO_ERROR_INVALID_RATE;
- goto error;
- }
- }
-
// Save device format so we can do format conversion and volume scaling together.
setDeviceFormat(configurationOutput.getFormat());
setDeviceSamplesPerFrame(configurationOutput.getSamplesPerFrame());
diff --git a/media/libaaudio/src/core/AAudioAudio.cpp b/media/libaaudio/src/core/AAudioAudio.cpp
index 64152f0..64f115c 100644
--- a/media/libaaudio/src/core/AAudioAudio.cpp
+++ b/media/libaaudio/src/core/AAudioAudio.cpp
@@ -26,6 +26,7 @@
#include <aaudio/AAudio.h>
#include <aaudio/AAudioTesting.h>
#include <system/aaudio/AAudio.h>
+#include <system/audio.h>
#include "AudioClock.h"
#include "AudioGlobal.h"
#include "AudioStreamBuilder.h"
@@ -182,15 +183,18 @@
streamBuilder->setContentType(contentType);
}
-AAUDIO_API aaudio_result_t AAudioStreamBuilder_setTags(AAudioStreamBuilder* builder,
- const char* tags) {
- if (tags == nullptr || strlen(tags) >= AAUDIO_ATTRIBUTES_TAGS_MAX_SIZE) {
+AAUDIO_API aaudio_result_t AAudioStreamBuilder_addTag(AAudioStreamBuilder* builder,
+ const char* tags) {
+ if (tags == nullptr) {
return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
}
AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
- std::optional<std::string> optionalTags = std::string(tags);
- streamBuilder->setTags(optionalTags);
- return AAUDIO_OK;
+ return streamBuilder->addTag(tags);
+}
+
+AAUDIO_API void AAudioStreamBuilder_clearTags(AAudioStreamBuilder* builder) {
+ AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
+ streamBuilder->clearTags();
}
AAUDIO_API void AAudioStreamBuilder_setSpatializationBehavior(AAudioStreamBuilder* builder,
@@ -255,6 +259,16 @@
streamBuilder->setErrorCallbackUserData(userData);
}
+AAUDIO_API void AAudioStreamBuilder_setPresentationEndCallback(AAudioStreamBuilder* builder,
+ AAudioStream_presentationEndCallback callback, void* userData) {
+ AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
+ if (streamBuilder == nullptr) {
+ return;
+ }
+ streamBuilder->setPresentationEndCallbackProc(callback)
+ ->setPresentationEndCallbackUserData(userData);
+}
+
AAUDIO_API void AAudioStreamBuilder_setFramesPerDataCallback(AAudioStreamBuilder* builder,
int32_t frames)
{
@@ -588,20 +602,43 @@
return audioStream->getContentType();
}
-AAUDIO_API aaudio_result_t AAudioStream_getTags(AAudioStream* stream, char* tags)
+AAUDIO_API int32_t AAudioStream_obtainTags(AAudioStream* stream, char*** tags)
{
+ AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+ auto aaTags = audioStream->getTags();
+ if (aaTags.empty()) {
+ *tags = nullptr;
+ return 0;
+ }
+ *tags = new char*[aaTags.size()];
+ if (*tags == nullptr) {
+ return AAUDIO_ERROR_NO_MEMORY;
+ }
+ auto it = aaTags.begin();
+ for (int i = 0; it != aaTags.end(); i++, it++) {
+ (*tags)[i] = new char[AUDIO_ATTRIBUTES_TAGS_MAX_SIZE];
+ if ((*tags)[i] == nullptr) {
+ for (int j = 0; j < i; ++j) {
+ delete[] (*tags)[i];
+ }
+ delete[] (*tags);
+ return AAUDIO_ERROR_NO_MEMORY;
+ }
+ strcpy((*tags)[i], it->c_str());
+ }
+ return aaTags.size();
+}
+
+AAUDIO_API void AAudioStream_releaseTags(AAudioStream* stream, char** tags) {
if (tags == nullptr) {
- return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+ return;
}
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
- std::optional<std::string> optTags = audioStream->getTags();
- if (optTags.has_value() && !optTags->empty()) {
- strncpy(tags, optTags.value().c_str(), AAUDIO_ATTRIBUTES_TAGS_MAX_SIZE);
- tags[AAUDIO_ATTRIBUTES_TAGS_MAX_SIZE-1] = '\0';
- } else {
- tags[0] = '\0';
+ const int tagsNum = audioStream->getTags().size();
+ for (int i = 0; i < tagsNum; ++i) {
+ delete[] tags[i];
}
- return AAUDIO_OK;
+ delete[] tags;
}
AAUDIO_API aaudio_spatialization_behavior_t AAudioStream_getSpatializationBehavior(
@@ -693,3 +730,27 @@
// Do not return channel index masks as they are not public.
return AAudio_isChannelIndexMask(channelMask) ? AAUDIO_UNSPECIFIED : channelMask;
}
+
+AAUDIO_API aaudio_result_t AAudioStream_setOffloadDelayPadding(
+ AAudioStream* stream, int32_t delayInFrames, int32_t paddingInFrames) {
+ if (delayInFrames < 0 || paddingInFrames < 0) {
+ return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+ }
+ AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+ return audioStream->setOffloadDelayPadding(delayInFrames, paddingInFrames);
+}
+
+AAUDIO_API int32_t AAudioStream_getOffloadDelay(AAudioStream* stream) {
+ AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+ return audioStream->getOffloadDelay();
+}
+
+AAUDIO_API int32_t AAudioStream_getOffloadPadding(AAudioStream* stream) {
+ AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+ return audioStream->getOffloadPadding();
+}
+
+AAUDIO_API aaudio_result_t AAudioStream_setOffloadEndOfStream(AAudioStream* stream) {
+ AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+ return audioStream->setOffloadEndOfStream();
+}
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.cpp b/media/libaaudio/src/core/AAudioStreamParameters.cpp
index f504fa9..3090fb2 100644
--- a/media/libaaudio/src/core/AAudioStreamParameters.cpp
+++ b/media/libaaudio/src/core/AAudioStreamParameters.cpp
@@ -16,6 +16,8 @@
#define LOG_TAG "AAudioStreamParameters"
+
+#include <android-base/strings.h>
#include <utils/Log.h>
#include <system/audio.h>
#include <system/aaudio/AAudio.h>
@@ -58,6 +60,13 @@
case AUDIO_FORMAT_PCM_24_BIT_PACKED:
case AUDIO_FORMAT_PCM_8_24_BIT:
case AUDIO_FORMAT_IEC61937:
+ case AUDIO_FORMAT_MP3:
+ case AUDIO_FORMAT_AAC_LC:
+ case AUDIO_FORMAT_AAC_HE_V1:
+ case AUDIO_FORMAT_AAC_HE_V2:
+ case AUDIO_FORMAT_AAC_ELD:
+ case AUDIO_FORMAT_AAC_XHE:
+ case AUDIO_FORMAT_OPUS:
break; // valid
default:
ALOGD("audioFormat not valid, audio_format_t = 0x%08x", format);
@@ -205,7 +214,7 @@
// break;
}
- if (mTags.has_value() && mTags->size() >= AAUDIO_ATTRIBUTES_TAGS_MAX_SIZE) {
+ if (getTagsAsString().size() >= AUDIO_ATTRIBUTES_TAGS_MAX_SIZE) {
return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
}
@@ -299,6 +308,10 @@
}
}
+std::string AAudioStreamParameters::getTagsAsString() const {
+ return android::base::Join(mTags, AUDIO_ATTRIBUTES_TAGS_SEPARATOR);
+}
+
void AAudioStreamParameters::dump() const {
ALOGD("mDeviceIds = %s", android::toString(mDeviceIds).c_str());
ALOGD("mSessionId = %6d", mSessionId);
@@ -311,7 +324,7 @@
ALOGD("mBufferCapacity = %6d", mBufferCapacity);
ALOGD("mUsage = %6d", mUsage);
ALOGD("mContentType = %6d", mContentType);
- ALOGD("mTags = %s", mTags.has_value() ? mTags.value().c_str() : "");
+ ALOGD("mTags = %s", getTagsAsString().c_str());
ALOGD("mSpatializationBehavior = %6d", mSpatializationBehavior);
ALOGD("mIsContentSpatialized = %s", mIsContentSpatialized ? "true" : "false");
ALOGD("mInputPreset = %6d", mInputPreset);
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.h b/media/libaaudio/src/core/AAudioStreamParameters.h
index c4c0a4f..94c5e89 100644
--- a/media/libaaudio/src/core/AAudioStreamParameters.h
+++ b/media/libaaudio/src/core/AAudioStreamParameters.h
@@ -98,14 +98,16 @@
mContentType = contentType;
}
- void setTags(const std::optional<std::string>& tags) {
+ void setTags(const std::set<std::string>& tags) {
mTags = tags;
}
- const std::optional<std::string> getTags() const {
+ const std::set<std::string>& getTags() const {
return mTags;
}
+ std::string getTagsAsString() const;
+
aaudio_spatialization_behavior_t getSpatializationBehavior() const {
return mSpatializationBehavior;
}
@@ -221,6 +223,9 @@
void dump() const;
+protected:
+ std::set<std::string> mTags;
+
private:
aaudio_result_t validateChannelMask() const;
@@ -232,7 +237,6 @@
aaudio_direction_t mDirection = AAUDIO_DIRECTION_OUTPUT;
aaudio_usage_t mUsage = AAUDIO_UNSPECIFIED;
aaudio_content_type_t mContentType = AAUDIO_UNSPECIFIED;
- std::optional<std::string> mTags = {};
aaudio_spatialization_behavior_t mSpatializationBehavior
= AAUDIO_UNSPECIFIED;
bool mIsContentSpatialized = false;
diff --git a/media/libaaudio/src/core/AudioGlobal.h b/media/libaaudio/src/core/AudioGlobal.h
index 7ff344b..c4ef87d 100644
--- a/media/libaaudio/src/core/AudioGlobal.h
+++ b/media/libaaudio/src/core/AudioGlobal.h
@@ -30,6 +30,8 @@
};
+static const char AUDIO_ATTRIBUTES_TAGS_SEPARATOR = ';';
+
aaudio_policy_t AudioGlobal_getMMapPolicy();
aaudio_result_t AudioGlobal_setMMapPolicy(aaudio_policy_t policy);
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index 8e3bcf7..fdda3b7 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -26,6 +26,7 @@
#include <sys/syscall.h>
#include <aaudio/AAudio.h>
+#include <android-base/strings.h>
#include "AudioStreamBuilder.h"
#include "AudioStream.h"
@@ -116,6 +117,8 @@
mErrorCallbackProc = builder.getErrorCallbackProc();
mDataCallbackUserData = builder.getDataCallbackUserData();
mErrorCallbackUserData = builder.getErrorCallbackUserData();
+ setPresentationEndCallbackUserData(builder.getPresentationEndCallbackUserData());
+ setPresentationEndCallbackProc(builder.getPresentationEndCallbackProc());
return AAUDIO_OK;
}
@@ -285,6 +288,10 @@
aaudio_result_t AudioStream::systemStopInternal() {
std::lock_guard<std::mutex> lock(mStreamLock);
+ return systemStopInternal_l();
+}
+
+aaudio_result_t AudioStream::systemStopInternal_l() {
aaudio_result_t result = safeStop_l();
if (result == AAUDIO_OK) {
// We only call this for logging in "dumpsys audio". So ignore return code.
@@ -653,6 +660,10 @@
return getState();
}
+std::string AudioStream::getTagsAsString() const {
+ return android::base::Join(mTags, AUDIO_ATTRIBUTES_TAGS_SEPARATOR);
+}
+
void AudioStream::MyPlayerBase::registerWithAudioManager(const android::sp<AudioStream>& parent) {
std::lock_guard<std::mutex> lock(mParentLock);
mParent = parent;
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index 3354adf..38ed5be 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -19,6 +19,7 @@
#include <atomic>
#include <mutex>
+#include <set>
#include <stdint.h>
#include <android-base/thread_annotations.h>
@@ -291,7 +292,7 @@
return mContentType;
}
- const std::optional<std::string> getTags() const {
+ const std::set<std::string>& getTags() const {
return mTags;
}
@@ -332,7 +333,7 @@
* have been called.
*/
int32_t getBytesPerFrame() const {
- return mSamplesPerFrame * getBytesPerSample();
+ return audio_bytes_per_frame(mSamplesPerFrame, mFormat);
}
/**
@@ -346,7 +347,7 @@
* This is only valid after setDeviceSamplesPerFrame() and setDeviceFormat() have been called.
*/
int32_t getBytesPerDeviceFrame() const {
- return getDeviceSamplesPerFrame() * audio_bytes_per_sample(getDeviceFormat());
+ return audio_bytes_per_frame(getDeviceSamplesPerFrame(), getDeviceFormat());
}
virtual int64_t getFramesWritten() = 0;
@@ -390,6 +391,24 @@
mDeviceSamplesPerFrame = deviceSamplesPerFrame;
}
+ virtual aaudio_result_t setOffloadDelayPadding(int32_t delayInFrames, int32_t paddingInFrames) {
+ return AAUDIO_ERROR_UNIMPLEMENTED;
+ }
+
+ virtual int32_t getOffloadDelay() {
+ return AAUDIO_ERROR_UNIMPLEMENTED;
+ }
+
+ virtual int32_t getOffloadPadding() {
+ return AAUDIO_ERROR_UNIMPLEMENTED;
+ }
+
+ virtual aaudio_result_t setOffloadEndOfStream() EXCLUDES(mStreamLock) {
+ return AAUDIO_ERROR_UNIMPLEMENTED;
+ }
+
+ virtual void setPresentationEndCallbackProc(AAudioStream_presentationEndCallback proc) { }
+ virtual void setPresentationEndCallbackUserData(void* userData) { }
/**
* @return true if data callback has been specified
@@ -408,7 +427,7 @@
/**
* @return true if called from the same thread as the callback
*/
- bool collidesWithCallback() const;
+ virtual bool collidesWithCallback() const;
// Implement AudioDeviceCallback
void onAudioDeviceUpdate(audio_io_handle_t audioIo,
@@ -649,6 +668,8 @@
aaudio_result_t joinThread_l(void **returnArg) REQUIRES(mStreamLock);
+ virtual aaudio_result_t systemStopInternal_l() REQUIRES(mStreamLock);
+
std::atomic<bool> mCallbackEnabled{false};
float mDuckAndMuteVolume = 1.0f;
@@ -695,10 +716,12 @@
/**
* This should not be called after the open() call.
*/
- void setTags(const std::optional<std::string> &tags) {
+ void setTags(const std::set<std::string> &tags) {
mTags = tags;
}
+ std::string getTagsAsString() const;
+
void setSpatializationBehavior(aaudio_spatialization_behavior_t spatializationBehavior) {
mSpatializationBehavior = spatializationBehavior;
}
@@ -742,6 +765,8 @@
mAudioBalance = audioBalance;
}
+ aaudio_result_t safeStop_l() REQUIRES(mStreamLock);
+
std::string mMetricsId; // set once during open()
std::mutex mStreamLock;
@@ -750,8 +775,6 @@
private:
- aaudio_result_t safeStop_l() REQUIRES(mStreamLock);
-
/**
* Release then close the stream.
*/
@@ -788,7 +811,7 @@
aaudio_usage_t mUsage = AAUDIO_UNSPECIFIED;
aaudio_content_type_t mContentType = AAUDIO_UNSPECIFIED;
- std::optional<std::string> mTags = {};
+ std::set<std::string> mTags;
aaudio_spatialization_behavior_t mSpatializationBehavior = AAUDIO_UNSPECIFIED;
bool mIsContentSpatialized = false;
aaudio_input_preset_t mInputPreset = AAUDIO_UNSPECIFIED;
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.cpp b/media/libaaudio/src/core/AudioStreamBuilder.cpp
index 73bd69f..a88052d 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.cpp
+++ b/media/libaaudio/src/core/AudioStreamBuilder.cpp
@@ -19,6 +19,7 @@
#include <utils/Log.h>
#include <new>
+#include <numeric>
#include <stdint.h>
#include <vector>
@@ -28,6 +29,7 @@
#include <android/media/audio/common/AudioMMapPolicyInfo.h>
#include <android/media/audio/common/AudioMMapPolicyType.h>
#include <media/AudioSystem.h>
+#include <system/aaudio/AAudio.h>
#include "binding/AAudioBinderClient.h"
#include "client/AudioStreamInternalCapture.h"
@@ -174,6 +176,11 @@
__func__);
allowMMap = false;
}
+ if (!audio_is_linear_pcm(getFormat())) {
+ ALOGD("%s() MMAP not used because the requested format(%#x) is not pcm",
+ __func__, getFormat());
+ allowMMap = false;
+ }
// SessionID and Effects are only supported in Legacy mode.
if (getSessionId() != AAUDIO_SESSION_ID_NONE) {
@@ -261,6 +268,14 @@
case AAUDIO_PERFORMANCE_MODE_POWER_SAVING:
case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY:
break;
+ case AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED:
+ if (getDirection() != AAUDIO_DIRECTION_OUTPUT ||
+ getFormat() == AUDIO_FORMAT_DEFAULT ||
+ getSampleRate() == 0 ||
+ getChannelMask() == AAUDIO_UNSPECIFIED) {
+ return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+ }
+ break;
default:
ALOGE("illegal performanceMode = %d", mPerformanceMode);
return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
@@ -279,6 +294,24 @@
return AAUDIO_OK;
}
+aaudio_result_t AudioStreamBuilder::addTag(const char* tag) {
+ const std::string tagStr(tag);
+ mTags.insert(tagStr);
+ // The tags will be joined with `;` and ended with null terminator when sending to the HAL.
+ const int tagsLength = std::accumulate(
+ mTags.begin(), mTags.end(), 0, [](int v, const std::string& s) { return v + s.size(); })
+ + mTags.size();
+ if (tagsLength <= AUDIO_ATTRIBUTES_TAGS_MAX_SIZE) {
+ return AAUDIO_OK;
+ }
+ mTags.erase(tagStr);
+ return AAUDIO_ERROR_OUT_OF_RANGE;
+}
+
+void AudioStreamBuilder::clearTags() {
+ mTags.clear();
+}
+
static const char *AAudio_convertSharingModeToShortText(aaudio_sharing_mode_t sharingMode) {
switch (sharingMode) {
case AAUDIO_SHARING_MODE_EXCLUSIVE:
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.h b/media/libaaudio/src/core/AudioStreamBuilder.h
index f91c25a..4f66f5b 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.h
+++ b/media/libaaudio/src/core/AudioStreamBuilder.h
@@ -17,6 +17,7 @@
#ifndef AAUDIO_AUDIO_STREAM_BUILDER_H
#define AAUDIO_AUDIO_STREAM_BUILDER_H
+#include <set>
#include <stdint.h>
#include <aaudio/AAudio.h>
@@ -89,6 +90,24 @@
return mErrorCallbackUserData;
}
+ AudioStreamBuilder* setPresentationEndCallbackProc(AAudioStream_presentationEndCallback proc) {
+ mPresentationEndCallbackProc = proc;
+ return this;
+ }
+
+ AAudioStream_presentationEndCallback getPresentationEndCallbackProc() const {
+ return mPresentationEndCallbackProc;
+ }
+
+ AudioStreamBuilder* setPresentationEndCallbackUserData(void *userData) {
+ mPresentationEndCallbackUserData = userData;
+ return this;
+ }
+
+ void *getPresentationEndCallbackUserData() const {
+ return mPresentationEndCallbackUserData;
+ }
+
int32_t getFramesPerDataCallback() const {
return mFramesPerDataCallback;
}
@@ -104,6 +123,10 @@
return this;
}
+ aaudio_result_t addTag(const char* tag);
+
+ void clearTags();
+
aaudio_result_t build(AudioStream **streamPtr);
virtual aaudio_result_t validate() const override;
@@ -128,6 +151,9 @@
AAudioStream_errorCallback mErrorCallbackProc = nullptr;
void *mErrorCallbackUserData = nullptr;
+ AAudioStream_presentationEndCallback mPresentationEndCallbackProc = nullptr;
+ void *mPresentationEndCallbackUserData = nullptr;
+
enum {
PRIVACY_SENSITIVE_DEFAULT = -1,
PRIVACY_SENSITIVE_DISABLED = 0,
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index 2e57f0d..f0a25b5 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -22,7 +22,9 @@
#include <media/AudioTrack.h>
#include <aaudio/AAudio.h>
+#include <com_android_media_aaudio.h>
#include <system/audio.h>
+#include <system/aaudio/AAudio.h>
#include "core/AudioGlobal.h"
#include "legacy/AudioStreamLegacy.h"
@@ -56,6 +58,10 @@
aaudio_result_t AudioStreamTrack::open(const AudioStreamBuilder& builder)
{
+ if (!com::android::media::aaudio::offload_support() &&
+ builder.getPerformanceMode() == AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED) {
+ return AAUDIO_ERROR_UNIMPLEMENTED;
+ }
aaudio_result_t result = AAUDIO_OK;
result = AudioStream::open(builder);
@@ -144,14 +150,43 @@
builder.isContentSpatialized(),
flags);
- const std::optional<std::string> tags = builder.getTags();
+ const std::string tags = getTagsAsString();
audio_attributes_t attributes = AUDIO_ATTRIBUTES_INITIALIZER;
attributes.content_type = contentType;
attributes.usage = usage;
attributes.flags = attributesFlags;
- if (tags.has_value() && !tags.value().empty()) {
- strcpy(attributes.tags, tags.value().c_str());
+ if (!tags.empty()) {
+ strncpy(attributes.tags, tags.c_str(), AUDIO_ATTRIBUTES_TAGS_MAX_SIZE);
+ attributes.tags[AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1] = '\0';
}
+
+ audio_offload_info_t offloadInfo = AUDIO_INFO_INITIALIZER;
+ if (getPerformanceMode() == AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED) {
+ audio_config_t config = AUDIO_CONFIG_INITIALIZER;
+ config.format = format;
+ config.channel_mask = channelMask;
+ config.sample_rate = getSampleRate();
+ audio_direct_mode_t directMode = AUDIO_DIRECT_NOT_SUPPORTED;
+ if (status_t status = AudioSystem::getDirectPlaybackSupport(
+ &attributes, &config, &directMode);
+ status != NO_ERROR) {
+ ALOGE("%s, failed to query direct support, error=%d", __func__, status);
+ return status;
+ }
+ static const audio_direct_mode_t offloadMode = static_cast<audio_direct_mode_t>(
+ AUDIO_DIRECT_OFFLOAD_SUPPORTED | AUDIO_DIRECT_OFFLOAD_GAPLESS_SUPPORTED);
+ if ((directMode & offloadMode) == AUDIO_DIRECT_NOT_SUPPORTED) {
+ return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+ }
+ flags = AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
+ frameCount = 0;
+ offloadInfo.format = format;
+ offloadInfo.sample_rate = getSampleRate();
+ offloadInfo.channel_mask = channelMask;
+ offloadInfo.has_video = false;
+ offloadInfo.stream_type = AUDIO_STREAM_MUSIC;
+ }
+
mAudioTrack = new AudioTrack();
// TODO b/182392769: use attribution source util
mAudioTrack->set(
@@ -167,7 +202,8 @@
false, // DEFAULT threadCanCallJava
sessionId,
streamTransferType,
- nullptr, // DEFAULT audio_offload_info_t
+ getPerformanceMode() == AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED
+ ? &offloadInfo : nullptr,
AttributionSourceState(), // DEFAULT uid and pid
&attributes,
// WARNING - If doNotReconnect set true then audio stops after plugging and unplugging
@@ -247,7 +283,9 @@
audio_output_flags_t actualFlags = mAudioTrack->getFlags();
aaudio_performance_mode_t actualPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE;
// We may not get the RAW flag. But as long as we get the FAST flag we can call it LOW_LATENCY.
- if ((actualFlags & AUDIO_OUTPUT_FLAG_FAST) != 0) {
+ if ((actualFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != AUDIO_OUTPUT_FLAG_NONE) {
+ actualPerformanceMode = AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED;
+ } else if ((actualFlags & AUDIO_OUTPUT_FLAG_FAST) != 0) {
actualPerformanceMode = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
} else if ((actualFlags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) != 0) {
actualPerformanceMode = AAUDIO_PERFORMANCE_MODE_POWER_SAVING;
@@ -347,6 +385,7 @@
setState(originalState);
return AAudioConvert_androidToAAudioResult(err);
}
+ mOffloadEosPending = false;
return AAUDIO_OK;
}
@@ -430,6 +469,12 @@
break;
case AAUDIO_STREAM_STATE_STOPPING:
if (mAudioTrack->stopped()) {
+ if (getPerformanceMode() == AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED) {
+ std::lock_guard<std::mutex> lock(mStreamLock);
+ if (!mOffloadEosPending) {
+ break;
+ }
+ }
setState(AAUDIO_STREAM_STATE_STOPPED);
}
break;
@@ -579,6 +624,104 @@
mAudioTrack->setPlayerIId(mPlayerBase->getPlayerIId());
}
+aaudio_result_t AudioStreamTrack::systemStopInternal_l() {
+ if (aaudio_result_t result = AudioStream::systemStopInternal_l(); result != AAUDIO_OK) {
+ return result;
+ }
+ mOffloadEosPending = false;
+ return AAUDIO_OK;
+}
+
+aaudio_result_t AudioStreamTrack::setOffloadDelayPadding(
+ int32_t delayInFrames, int32_t paddingInFrames) {
+ if (getPerformanceMode() != AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED ||
+ audio_is_linear_pcm(getFormat())) {
+ return AAUDIO_ERROR_UNIMPLEMENTED;
+ }
+ if (mAudioTrack == nullptr) {
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
+ AudioParameter param = AudioParameter();
+ param.addInt(String8(AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES), delayInFrames);
+ param.addInt(String8(AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES), paddingInFrames);
+ mAudioTrack->setParameters(param.toString());
+ mOffloadDelayFrames.store(delayInFrames);
+ mOffloadPaddingFrames.store(paddingInFrames);
+ return AAUDIO_OK;
+}
+
+int32_t AudioStreamTrack::getOffloadDelay() {
+ if (getPerformanceMode() != AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED ||
+ audio_is_linear_pcm(getFormat())) {
+ return AAUDIO_ERROR_UNIMPLEMENTED;
+ }
+ if (mAudioTrack == nullptr) {
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
+ return mOffloadDelayFrames.load();
+}
+
+int32_t AudioStreamTrack::getOffloadPadding() {
+ if (getPerformanceMode() != AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED ||
+ audio_is_linear_pcm(getFormat())) {
+ return AAUDIO_ERROR_UNIMPLEMENTED;
+ }
+ if (mAudioTrack == nullptr) {
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
+ return mOffloadPaddingFrames.load();
+}
+
+aaudio_result_t AudioStreamTrack::setOffloadEndOfStream() {
+ if (getPerformanceMode() != AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED) {
+ return AAUDIO_ERROR_UNIMPLEMENTED;
+ }
+ if (mAudioTrack == nullptr) {
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
+ std::lock_guard<std::mutex> lock(mStreamLock);
+ if (aaudio_result_t result = safeStop_l(); result != AAUDIO_OK) {
+ return result;
+ }
+ mOffloadEosPending = true;
+ return AAUDIO_OK;
+}
+
+bool AudioStreamTrack::collidesWithCallback() const {
+ if (AudioStream::collidesWithCallback()) {
+ return true;
+ }
+ pid_t thisThread = gettid();
+ return mPresentationEndCallbackThread.load() == thisThread;
+}
+
+void AudioStreamTrack::onStreamEnd() {
+ if (getPerformanceMode() != AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED) {
+ return;
+ }
+ if (getState() == AAUDIO_STREAM_STATE_STOPPING) {
+ std::lock_guard<std::mutex> lock(mStreamLock);
+ if (mOffloadEosPending) {
+ requestStart_l();
+ }
+ mOffloadEosPending = false;
+ }
+ maybeCallPresentationEndCallback();
+}
+
+void AudioStreamTrack::maybeCallPresentationEndCallback() {
+ if (mPresentationEndCallbackProc != nullptr) {
+ pid_t expected = CALLBACK_THREAD_NONE;
+ if (mPresentationEndCallbackThread.compare_exchange_strong(expected, gettid())) {
+ (*mPresentationEndCallbackProc)(
+ (AAudioStream *) this, mPresentationEndCallbackUserData);
+ mPresentationEndCallbackThread.store(CALLBACK_THREAD_NONE);
+ } else {
+ ALOGW("%s() error callback already running!", __func__);
+ }
+ }
+}
+
#if AAUDIO_USE_VOLUME_SHAPER
using namespace android::media::VolumeShaper;
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.h b/media/libaaudio/src/legacy/AudioStreamTrack.h
index 05609c4..82ba772 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.h
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.h
@@ -49,6 +49,11 @@
aaudio_result_t requestPause_l() REQUIRES(mStreamLock) override;
aaudio_result_t requestFlush_l() REQUIRES(mStreamLock) override;
aaudio_result_t requestStop_l() REQUIRES(mStreamLock) override;
+ aaudio_result_t systemStopInternal_l() REQUIRES(mStreamLock) final;
+
+ bool collidesWithCallback() const final;
+
+ void onStreamEnd() final;
public:
bool isFlushSupported() const override {
@@ -89,6 +94,26 @@
void registerPlayerBase() override;
+ // Offload begin --------------------------------------
+ aaudio_result_t setOffloadDelayPadding(int32_t delayInFrames, int32_t paddingInFrames) final;
+
+ int32_t getOffloadDelay() final;
+
+ int32_t getOffloadPadding() final;
+
+ aaudio_result_t setOffloadEndOfStream() EXCLUDES(mStreamLock) final;
+
+ void setPresentationEndCallbackProc(AAudioStream_presentationEndCallback proc) final {
+ mPresentationEndCallbackProc = proc;
+ }
+
+ virtual void setPresentationEndCallbackUserData(void *userData) final {
+ mPresentationEndCallbackUserData = userData;
+ }
+
+ void maybeCallPresentationEndCallback();
+ // Offload end ----------------------------------------
+
#if AAUDIO_USE_VOLUME_SHAPER
virtual android::binder::Status applyVolumeShaper(
const android::media::VolumeShaper::Configuration& configuration,
@@ -110,6 +135,15 @@
// TODO add 64-bit position reporting to AudioTrack and use it.
aaudio_wrapping_frames_t mPositionWhenPausing = 0;
+
+ // Offload --------------------------------------------
+ std::atomic<int32_t> mOffloadDelayFrames = 0;
+ std::atomic<int32_t> mOffloadPaddingFrames = 0;
+ bool mOffloadEosPending GUARDED_BY(mStreamLock) = false;
+
+ AAudioStream_presentationEndCallback mPresentationEndCallbackProc = nullptr;
+ void *mPresentationEndCallbackUserData = nullptr;
+ std::atomic<pid_t> mPresentationEndCallbackThread{CALLBACK_THREAD_NONE};
};
} /* namespace aaudio */
diff --git a/media/libaaudio/src/libaaudio.map.txt b/media/libaaudio/src/libaaudio.map.txt
index 36d76aa..2425ae4 100644
--- a/media/libaaudio/src/libaaudio.map.txt
+++ b/media/libaaudio/src/libaaudio.map.txt
@@ -28,6 +28,7 @@
AAudioStreamBuilder_setChannelMask; # introduced=32
AAudioStreamBuilder_setSpatializationBehavior; # introduced=32
AAudioStreamBuilder_setIsContentSpatialized; # introduced=32
+ AAudioStreamBuilder_setPresentationEndCallback; #introduced=36
AAudioStreamBuilder_openStream;
AAudioStreamBuilder_delete;
AAudioStream_close;
@@ -73,9 +74,15 @@
AAudio_getPlatformMMapPolicy; # introduced=36
AAudio_getPlatformMMapExclusivePolicy; #introduced=36
AAudioStream_getDeviceIds; # introduced=36
+ AAudioStream_setOffloadDelayPadding; #introduced=36
+ AAudioStream_getOffloadDelay; #introduced=36
+ AAudioStream_getOffloadPadding; #introduced=36
+ AAudioStream_setOffloadEndOfStream; #introduced=36
- AAudioStreamBuilder_setTags; # systemapi
- AAudioStream_getTags; # systemapi
+ AAudioStreamBuilder_addTag; # systemapi
+ AAudioStreamBuilder_clearTags; # systemapi
+ AAudioStream_obtainTags; # systemapi
+ AAudioStream_releaseTags; #systemapi
local:
*;
};
diff --git a/media/libaaudio/src/utility/AAudioUtilities.cpp b/media/libaaudio/src/utility/AAudioUtilities.cpp
index c741946..873fcba 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.cpp
+++ b/media/libaaudio/src/utility/AAudioUtilities.cpp
@@ -147,6 +147,27 @@
case AAUDIO_FORMAT_IEC61937:
androidFormat = AUDIO_FORMAT_IEC61937;
break;
+ case AAUDIO_FORMAT_MP3:
+ androidFormat = AUDIO_FORMAT_MP3;
+ break;
+ case AAUDIO_FORMAT_AAC_LC:
+ androidFormat = AUDIO_FORMAT_AAC_LC;
+ break;
+ case AAUDIO_FORMAT_AAC_HE_V1:
+ androidFormat = AUDIO_FORMAT_AAC_HE_V1;
+ break;
+ case AAUDIO_FORMAT_AAC_HE_V2:
+ androidFormat = AUDIO_FORMAT_AAC_HE_V2;
+ break;
+ case AAUDIO_FORMAT_AAC_ELD:
+ androidFormat = AUDIO_FORMAT_AAC_ELD;
+ break;
+ case AAUDIO_FORMAT_AAC_XHE:
+ androidFormat = AUDIO_FORMAT_AAC_XHE;
+ break;
+ case AAUDIO_FORMAT_OPUS:
+ androidFormat = AUDIO_FORMAT_OPUS;
+ break;
default:
androidFormat = AUDIO_FORMAT_INVALID;
ALOGE("%s() 0x%08X unrecognized", __func__, aaudioFormat);
@@ -176,6 +197,27 @@
case AUDIO_FORMAT_IEC61937:
aaudioFormat = AAUDIO_FORMAT_IEC61937;
break;
+ case AUDIO_FORMAT_MP3:
+ aaudioFormat = AAUDIO_FORMAT_MP3;
+ break;
+ case AUDIO_FORMAT_AAC_LC:
+ aaudioFormat = AAUDIO_FORMAT_AAC_LC;
+ break;
+ case AUDIO_FORMAT_AAC_HE_V1:
+ aaudioFormat = AAUDIO_FORMAT_AAC_HE_V1;
+ break;
+ case AUDIO_FORMAT_AAC_HE_V2:
+ aaudioFormat = AAUDIO_FORMAT_AAC_HE_V2;
+ break;
+ case AUDIO_FORMAT_AAC_ELD:
+ aaudioFormat = AAUDIO_FORMAT_AAC_ELD;
+ break;
+ case AUDIO_FORMAT_AAC_XHE:
+ aaudioFormat = AAUDIO_FORMAT_AAC_XHE;
+ break;
+ case AUDIO_FORMAT_OPUS:
+ aaudioFormat = AAUDIO_FORMAT_OPUS;
+ break;
default:
aaudioFormat = AAUDIO_FORMAT_INVALID;
ALOGE("%s() 0x%08X unrecognized", __func__, androidFormat);
diff --git a/media/libaaudio/src/utility/AAudioUtilities.h b/media/libaaudio/src/utility/AAudioUtilities.h
index d5069f5..940e4b5 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.h
+++ b/media/libaaudio/src/utility/AAudioUtilities.h
@@ -373,4 +373,6 @@
aaudio_policy_t AAudioConvert_androidToAAudioMMapPolicy(
android::media::audio::common::AudioMMapPolicy policy);
+bool AAudio_isCompressedFormat(audio_format_t format);
+
#endif //UTILITY_AAUDIO_UTILITIES_H
diff --git a/media/libaaudio/tests/test_attributes.cpp b/media/libaaudio/tests/test_attributes.cpp
index 045c236..fcb083d 100644
--- a/media/libaaudio/tests/test_attributes.cpp
+++ b/media/libaaudio/tests/test_attributes.cpp
@@ -14,15 +14,19 @@
* limitations under the License.
*/
-// Test AAudio attributes such as Usage, ContentType and InputPreset.
+// Test AAudio attributes such as Usage, ContentType, InputPreset and Tags.
// TODO Many of these tests are duplicates of CTS tests in
// "test_aaudio_attributes.cpp". That other file is more current.
// So these tests could be deleted.
+// Also note audio attributes tags, which is system api, it cannot be tested
+// from the CTS. In that case, please do not delete audio attributes tags test.
+#include <algorithm>
#include <memory>
#include <stdio.h>
#include <unistd.h>
+#include <vector>
#include <aaudio/AAudio.h>
#include <gtest/gtest.h>
@@ -38,17 +42,18 @@
static void checkAttributes(aaudio_performance_mode_t perfMode,
aaudio_usage_t usage,
aaudio_content_type_t contentType,
- const char * tags = nullptr,
+ std::vector<const char*>* tags = nullptr,
aaudio_input_preset_t preset = DONT_SET,
aaudio_allowed_capture_policy_t capturePolicy = DONT_SET,
int privacyMode = DONT_SET,
- aaudio_direction_t direction = AAUDIO_DIRECTION_OUTPUT) {
+ aaudio_direction_t direction = AAUDIO_DIRECTION_OUTPUT,
+ const char* tagToBeCleared = "TagsToBeCleared") {
std::unique_ptr<float[]> buffer(new float[kNumFrames * kChannelCount]);
AAudioStreamBuilder *aaudioBuilder = nullptr;
AAudioStream *aaudioStream = nullptr;
- aaudio_result_t expectedSetTagsResult = AAUDIO_OK;
+ aaudio_result_t expectedAddTagResult = AAUDIO_OK;
// Use an AAudioStreamBuilder to contain requested parameters.
ASSERT_EQ(AAUDIO_OK, AAudio_createStreamBuilder(&aaudioBuilder));
@@ -64,11 +69,32 @@
if (contentType != DONT_SET) {
AAudioStreamBuilder_setContentType(aaudioBuilder, contentType);
}
+ std::set<std::string> addedTags;
if (tags != nullptr) {
- aaudio_result_t result = AAudioStreamBuilder_setTags(aaudioBuilder, tags);
- expectedSetTagsResult = (strlen(tags) >= AUDIO_ATTRIBUTES_TAGS_MAX_SIZE) ?
- AAUDIO_ERROR_ILLEGAL_ARGUMENT : AAUDIO_OK;
- EXPECT_EQ(result, expectedSetTagsResult);
+ EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_addTag(aaudioBuilder, tagToBeCleared));
+ AAudioStreamBuilder_clearTags(aaudioBuilder);
+ int totalLength = 0;
+ for (int i = 0; i < tags->size(); ++i) {
+ if (tags->at(i) == nullptr) {
+ EXPECT_EQ(AAUDIO_ERROR_ILLEGAL_ARGUMENT,
+ AAudioStreamBuilder_addTag(aaudioBuilder, tags->at(i)));
+ continue;
+ }
+ // When sending all tags across the framework and the HAL, all tags are joined as a
+ // string. In that case, a delimiter will be added if the tag is not the last added
+ // tag or NULL terminator will be added if the tag is the last added tag.
+ int lengthToAdd = strlen(tags->at(i)) + 1;
+ totalLength += lengthToAdd;
+ aaudio_result_t result = AAudioStreamBuilder_addTag(aaudioBuilder, tags->at(i));
+ expectedAddTagResult = (totalLength > AUDIO_ATTRIBUTES_TAGS_MAX_SIZE) ?
+ AAUDIO_ERROR_OUT_OF_RANGE : AAUDIO_OK;
+ EXPECT_EQ(result, expectedAddTagResult) << "total length=" << totalLength;
+ if (expectedAddTagResult != AAUDIO_OK) {
+ totalLength -= lengthToAdd;
+ } else {
+ addedTags.insert(tags->at(i));
+ }
+ }
}
if (preset != DONT_SET) {
AAudioStreamBuilder_setInputPreset(aaudioBuilder, preset);
@@ -97,19 +123,16 @@
: contentType;
EXPECT_EQ(expectedContentType, AAudioStream_getContentType(aaudioStream));
- char readTags[AAUDIO_ATTRIBUTES_TAGS_MAX_SIZE] = {};
- EXPECT_EQ(AAUDIO_OK, AAudioStream_getTags(aaudioStream, readTags))
- << "Expected tags=" << (tags != nullptr ? tags : "null") << ", got tags=" << readTags;;
- EXPECT_LT(strlen(readTags), AUDIO_ATTRIBUTES_TAGS_MAX_SIZE)
- << "expected tags len " << strlen(readTags) << " less than "
- << AUDIO_ATTRIBUTES_TAGS_MAX_SIZE;
-
- // Null tags or failed to set, empty tags expected (default initializer)
- const char * expectedTags = tags == nullptr ?
- "" : (expectedSetTagsResult != AAUDIO_OK ? "" : tags);
- // Oversized tags will be discarded
- EXPECT_TRUE(std::strcmp(expectedTags, readTags) == 0)
- << "Expected tags=" << expectedTags << ", got tags=" << readTags;
+ char** readTags = nullptr;
+ const int32_t numOfTagsRead = AAudioStream_obtainTags(aaudioStream, &readTags);
+ EXPECT_EQ(addedTags.size(), numOfTagsRead);
+ EXPECT_EQ(numOfTagsRead == 0, readTags == nullptr);
+ std::set<std::string> readTagsSet;
+ for (int i = 0; i < numOfTagsRead; ++i) {
+ readTagsSet.insert(readTags[i]);
+ }
+ EXPECT_EQ(addedTags, readTagsSet);
+ AAudioStream_releaseTags(aaudioStream, readTags);
aaudio_input_preset_t expectedPreset =
(preset == DONT_SET || preset == AAUDIO_UNSPECIFIED)
@@ -167,7 +190,8 @@
static const std::string oversizedTags = std::string(AUDIO_ATTRIBUTES_TAGS_MAX_SIZE, 'B');
static const std::string maxSizeTags = std::string(AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1, 'C');
-static const char * const sTags[] = {
+static const int TOTAL_TAGS = 7;
+static const char * const sTags[TOTAL_TAGS] = {
nullptr,
"",
"oem=routing_extension",
@@ -225,8 +249,13 @@
}
static void checkAttributesTags(aaudio_performance_mode_t perfMode) {
- for (const char * const tags : sTags) {
- checkAttributes(perfMode, DONT_SET, DONT_SET, tags);
+ checkAttributes(perfMode, DONT_SET, DONT_SET, nullptr /*tags*/);
+ for (int i = 0; i < TOTAL_TAGS; ++i) {
+ std::vector<const char*> tags = {sTags[i]};
+ if (i > 0) {
+ tags.push_back(sTags[i-1]);
+ }
+ checkAttributes(perfMode, DONT_SET, DONT_SET, &tags);
}
}
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index 61204ae..6dfb327 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -359,6 +359,8 @@
"aidl/android/media/AudioMixerBehavior.aidl",
"aidl/android/media/AudioOffloadMode.aidl",
"aidl/android/media/AudioPolicyDeviceState.aidl",
+ "aidl/android/media/AudioPolicyForceUse.aidl",
+ "aidl/android/media/AudioPolicyForcedConfig.aidl",
"aidl/android/media/AudioProductStrategy.aidl",
"aidl/android/media/AudioVolumeGroup.aidl",
"aidl/android/media/DeviceRole.aidl",
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index cfa3011..dcfef45 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -62,8 +62,6 @@
using media::audio::common::AudioMMapPolicyInfo;
using media::audio::common::AudioMMapPolicyType;
using media::audio::common::AudioOffloadInfo;
-using media::audio::common::AudioPolicyForceUse;
-using media::audio::common::AudioPolicyForcedConfig;
using media::audio::common::AudioSource;
using media::audio::common::AudioStreamType;
using media::audio::common::AudioUsage;
@@ -1193,9 +1191,9 @@
if (aps == nullptr) return AUDIO_POLICY_FORCE_NONE;
auto result = [&]() -> ConversionResult<audio_policy_forced_cfg_t> {
- AudioPolicyForceUse usageAidl = VALUE_OR_RETURN(
+ media::AudioPolicyForceUse usageAidl = VALUE_OR_RETURN(
legacy2aidl_audio_policy_force_use_t_AudioPolicyForceUse(usage));
- AudioPolicyForcedConfig configAidl;
+ media::AudioPolicyForcedConfig configAidl;
RETURN_IF_ERROR(statusTFromBinderStatus(
aps->getForceUse(usageAidl, &configAidl)));
return aidl2legacy_AudioPolicyForcedConfig_audio_policy_forced_cfg_t(configAidl);
diff --git a/media/libaudioclient/AudioTrackShared.cpp b/media/libaudioclient/AudioTrackShared.cpp
index e3b79b2..359f3c1 100644
--- a/media/libaudioclient/AudioTrackShared.cpp
+++ b/media/libaudioclient/AudioTrackShared.cpp
@@ -310,8 +310,16 @@
ts = NULL;
break;
}
+
int32_t old = android_atomic_and(~CBLK_FUTEX_WAKE, &cblk->mFutex);
- if (!(old & CBLK_FUTEX_WAKE)) {
+
+ // Check inactive to prevent waiting if the track has been disabled due to underrun
+ // (or invalidated). The subsequent call to obtainBufer will return NOT_ENOUGH_DATA
+ // (or DEAD_OBJECT) and restart (or restore) the track.
+ const int32_t current_flags = android_atomic_acquire_load(&cblk->mFlags);
+ const bool inactive = current_flags & (CBLK_INVALID | CBLK_DISABLED);
+
+ if (!(old & CBLK_FUTEX_WAKE) && !inactive) {
if (measure && !beforeIsValid) {
clock_gettime(CLOCK_MONOTONIC, &before);
beforeIsValid = true;
diff --git a/media/libaudioclient/PolicyAidlConversion.cpp b/media/libaudioclient/PolicyAidlConversion.cpp
index a414cb7..163a359 100644
--- a/media/libaudioclient/PolicyAidlConversion.cpp
+++ b/media/libaudioclient/PolicyAidlConversion.cpp
@@ -296,6 +296,138 @@
return unexpected(BAD_VALUE);
}
+ConversionResult<audio_policy_force_use_t>
+aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t(media::AudioPolicyForceUse aidl) {
+ switch (aidl) {
+ case media::AudioPolicyForceUse::COMMUNICATION:
+ return AUDIO_POLICY_FORCE_FOR_COMMUNICATION;
+ case media::AudioPolicyForceUse::MEDIA:
+ return AUDIO_POLICY_FORCE_FOR_MEDIA;
+ case media::AudioPolicyForceUse::RECORD:
+ return AUDIO_POLICY_FORCE_FOR_RECORD;
+ case media::AudioPolicyForceUse::DOCK:
+ return AUDIO_POLICY_FORCE_FOR_DOCK;
+ case media::AudioPolicyForceUse::SYSTEM:
+ return AUDIO_POLICY_FORCE_FOR_SYSTEM;
+ case media::AudioPolicyForceUse::HDMI_SYSTEM_AUDIO:
+ return AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO;
+ case media::AudioPolicyForceUse::ENCODED_SURROUND:
+ return AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND;
+ case media::AudioPolicyForceUse::VIBRATE_RINGING:
+ return AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<media::AudioPolicyForceUse>
+legacy2aidl_audio_policy_force_use_t_AudioPolicyForceUse(audio_policy_force_use_t legacy) {
+ switch (legacy) {
+ case AUDIO_POLICY_FORCE_FOR_COMMUNICATION:
+ return media::AudioPolicyForceUse::COMMUNICATION;
+ case AUDIO_POLICY_FORCE_FOR_MEDIA:
+ return media::AudioPolicyForceUse::MEDIA;
+ case AUDIO_POLICY_FORCE_FOR_RECORD:
+ return media::AudioPolicyForceUse::RECORD;
+ case AUDIO_POLICY_FORCE_FOR_DOCK:
+ return media::AudioPolicyForceUse::DOCK;
+ case AUDIO_POLICY_FORCE_FOR_SYSTEM:
+ return media::AudioPolicyForceUse::SYSTEM;
+ case AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO:
+ return media::AudioPolicyForceUse::HDMI_SYSTEM_AUDIO;
+ case AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND:
+ return media::AudioPolicyForceUse::ENCODED_SURROUND;
+ case AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING:
+ return media::AudioPolicyForceUse::VIBRATE_RINGING;
+ case AUDIO_POLICY_FORCE_USE_CNT:
+ break;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<audio_policy_forced_cfg_t>
+aidl2legacy_AudioPolicyForcedConfig_audio_policy_forced_cfg_t(media::AudioPolicyForcedConfig aidl) {
+ switch (aidl) {
+ case media::AudioPolicyForcedConfig::NONE:
+ return AUDIO_POLICY_FORCE_NONE;
+ case media::AudioPolicyForcedConfig::SPEAKER:
+ return AUDIO_POLICY_FORCE_SPEAKER;
+ case media::AudioPolicyForcedConfig::HEADPHONES:
+ return AUDIO_POLICY_FORCE_HEADPHONES;
+ case media::AudioPolicyForcedConfig::BT_SCO:
+ return AUDIO_POLICY_FORCE_BT_SCO;
+ case media::AudioPolicyForcedConfig::BT_A2DP:
+ return AUDIO_POLICY_FORCE_BT_A2DP;
+ case media::AudioPolicyForcedConfig::WIRED_ACCESSORY:
+ return AUDIO_POLICY_FORCE_WIRED_ACCESSORY;
+ case media::AudioPolicyForcedConfig::BT_CAR_DOCK:
+ return AUDIO_POLICY_FORCE_BT_CAR_DOCK;
+ case media::AudioPolicyForcedConfig::BT_DESK_DOCK:
+ return AUDIO_POLICY_FORCE_BT_DESK_DOCK;
+ case media::AudioPolicyForcedConfig::ANALOG_DOCK:
+ return AUDIO_POLICY_FORCE_ANALOG_DOCK;
+ case media::AudioPolicyForcedConfig::DIGITAL_DOCK:
+ return AUDIO_POLICY_FORCE_DIGITAL_DOCK;
+ case media::AudioPolicyForcedConfig::NO_BT_A2DP:
+ return AUDIO_POLICY_FORCE_NO_BT_A2DP;
+ case media::AudioPolicyForcedConfig::SYSTEM_ENFORCED:
+ return AUDIO_POLICY_FORCE_SYSTEM_ENFORCED;
+ case media::AudioPolicyForcedConfig::HDMI_SYSTEM_AUDIO_ENFORCED:
+ return AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED;
+ case media::AudioPolicyForcedConfig::ENCODED_SURROUND_NEVER:
+ return AUDIO_POLICY_FORCE_ENCODED_SURROUND_NEVER;
+ case media::AudioPolicyForcedConfig::ENCODED_SURROUND_ALWAYS:
+ return AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS;
+ case media::AudioPolicyForcedConfig::ENCODED_SURROUND_MANUAL:
+ return AUDIO_POLICY_FORCE_ENCODED_SURROUND_MANUAL;
+ case media::AudioPolicyForcedConfig::BT_BLE:
+ return AUDIO_POLICY_FORCE_BT_BLE;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<media::AudioPolicyForcedConfig>
+legacy2aidl_audio_policy_forced_cfg_t_AudioPolicyForcedConfig(audio_policy_forced_cfg_t legacy) {
+ switch (legacy) {
+ case AUDIO_POLICY_FORCE_NONE:
+ return media::AudioPolicyForcedConfig::NONE;
+ case AUDIO_POLICY_FORCE_SPEAKER:
+ return media::AudioPolicyForcedConfig::SPEAKER;
+ case AUDIO_POLICY_FORCE_HEADPHONES:
+ return media::AudioPolicyForcedConfig::HEADPHONES;
+ case AUDIO_POLICY_FORCE_BT_SCO:
+ return media::AudioPolicyForcedConfig::BT_SCO;
+ case AUDIO_POLICY_FORCE_BT_A2DP:
+ return media::AudioPolicyForcedConfig::BT_A2DP;
+ case AUDIO_POLICY_FORCE_WIRED_ACCESSORY:
+ return media::AudioPolicyForcedConfig::WIRED_ACCESSORY;
+ case AUDIO_POLICY_FORCE_BT_CAR_DOCK:
+ return media::AudioPolicyForcedConfig::BT_CAR_DOCK;
+ case AUDIO_POLICY_FORCE_BT_DESK_DOCK:
+ return media::AudioPolicyForcedConfig::BT_DESK_DOCK;
+ case AUDIO_POLICY_FORCE_ANALOG_DOCK:
+ return media::AudioPolicyForcedConfig::ANALOG_DOCK;
+ case AUDIO_POLICY_FORCE_DIGITAL_DOCK:
+ return media::AudioPolicyForcedConfig::DIGITAL_DOCK;
+ case AUDIO_POLICY_FORCE_NO_BT_A2DP:
+ return media::AudioPolicyForcedConfig::NO_BT_A2DP;
+ case AUDIO_POLICY_FORCE_SYSTEM_ENFORCED:
+ return media::AudioPolicyForcedConfig::SYSTEM_ENFORCED;
+ case AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED:
+ return media::AudioPolicyForcedConfig::HDMI_SYSTEM_AUDIO_ENFORCED;
+ case AUDIO_POLICY_FORCE_ENCODED_SURROUND_NEVER:
+ return media::AudioPolicyForcedConfig::ENCODED_SURROUND_NEVER;
+ case AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS:
+ return media::AudioPolicyForcedConfig::ENCODED_SURROUND_ALWAYS;
+ case AUDIO_POLICY_FORCE_ENCODED_SURROUND_MANUAL:
+ return media::AudioPolicyForcedConfig::ENCODED_SURROUND_MANUAL;
+ case AUDIO_POLICY_FORCE_BT_BLE:
+ return media::AudioPolicyForcedConfig::BT_BLE;
+ case AUDIO_POLICY_FORCE_CFG_CNT:
+ break;
+ }
+ return unexpected(BAD_VALUE);
+}
+
ConversionResult<device_role_t>
aidl2legacy_DeviceRole_device_role_t(media::DeviceRole aidl) {
switch (aidl) {
diff --git a/media/libaudioclient/aidl/android/media/AudioPolicyForceUse.aidl b/media/libaudioclient/aidl/android/media/AudioPolicyForceUse.aidl
new file mode 100644
index 0000000..9bb0605
--- /dev/null
+++ b/media/libaudioclient/aidl/android/media/AudioPolicyForceUse.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media;
+
+/**
+ * {@hide}
+ */
+@Backing(type="int")
+enum AudioPolicyForceUse {
+ COMMUNICATION = 0,
+ MEDIA = 1,
+ RECORD = 2,
+ DOCK = 3,
+ SYSTEM = 4,
+ HDMI_SYSTEM_AUDIO = 5,
+ ENCODED_SURROUND = 6,
+ VIBRATE_RINGING = 7,
+}
diff --git a/media/libaudioclient/aidl/android/media/AudioPolicyForcedConfig.aidl b/media/libaudioclient/aidl/android/media/AudioPolicyForcedConfig.aidl
new file mode 100644
index 0000000..111bb2f
--- /dev/null
+++ b/media/libaudioclient/aidl/android/media/AudioPolicyForcedConfig.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media;
+
+/**
+ * {@hide}
+ */
+@Backing(type="int")
+enum AudioPolicyForcedConfig {
+ NONE = 0,
+ SPEAKER = 1,
+ HEADPHONES = 2,
+ BT_SCO = 3,
+ BT_A2DP = 4,
+ WIRED_ACCESSORY = 5,
+ BT_CAR_DOCK = 6,
+ BT_DESK_DOCK = 7,
+ ANALOG_DOCK = 8,
+ DIGITAL_DOCK = 9,
+ NO_BT_A2DP = 10, /* A2DP sink is not preferred to speaker or wired HS */
+ SYSTEM_ENFORCED = 11,
+ HDMI_SYSTEM_AUDIO_ENFORCED = 12,
+ ENCODED_SURROUND_NEVER = 13,
+ ENCODED_SURROUND_ALWAYS = 14,
+ ENCODED_SURROUND_MANUAL = 15,
+ BT_BLE = 16,
+}
diff --git a/media/libaudioclient/aidl/android/media/GetInputForAttrResponse.aidl b/media/libaudioclient/aidl/android/media/GetInputForAttrResponse.aidl
index 347bf79..9e57820 100644
--- a/media/libaudioclient/aidl/android/media/GetInputForAttrResponse.aidl
+++ b/media/libaudioclient/aidl/android/media/GetInputForAttrResponse.aidl
@@ -28,6 +28,8 @@
int selectedDeviceId;
/** Interpreted as audio_port_handle_t. */
int portId;
+ /** The virtual device id corresponding to the opened input. */
+ int virtualDeviceId;
/** The suggested config if fails to get an input. **/
AudioConfigBase config;
}
diff --git a/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl b/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
index 7f4a7dd..fab2d95 100644
--- a/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
@@ -25,6 +25,8 @@
import android.media.AudioOffloadMode;
import android.media.AudioPatchFw;
import android.media.AudioPolicyDeviceState;
+import android.media.AudioPolicyForcedConfig;
+import android.media.AudioPolicyForceUse;
import android.media.AudioPortFw;
import android.media.AudioPortConfigFw;
import android.media.AudioPortRole;
@@ -49,8 +51,6 @@
import android.media.audio.common.AudioMMapPolicyInfo;
import android.media.audio.common.AudioMMapPolicyType;
import android.media.audio.common.AudioMode;
-import android.media.audio.common.AudioPolicyForcedConfig;
-import android.media.audio.common.AudioPolicyForceUse;
import android.media.audio.common.AudioProfile;
import android.media.audio.common.AudioOffloadInfo;
import android.media.audio.common.AudioPort;
diff --git a/media/libaudioclient/aidl/android/media/ISpatializer.aidl b/media/libaudioclient/aidl/android/media/ISpatializer.aidl
index 37dd776..4a5321e 100644
--- a/media/libaudioclient/aidl/android/media/ISpatializer.aidl
+++ b/media/libaudioclient/aidl/android/media/ISpatializer.aidl
@@ -163,4 +163,11 @@
* Gets the io handle of the output stream the spatializer is connected to.
*/
int getOutput();
+
+ /**
+ * Returns a list of channel masks that represent the widest channel masks the spatializer
+ * is capable of rendering with individual channel positions.
+ * Note that each channel mask is in the native format.
+ */
+ int[] getSpatializedChannelMasks();
}
diff --git a/media/libaudioclient/aidl/fuzzer/Android.bp b/media/libaudioclient/aidl/fuzzer/Android.bp
index 14e528f..05db9e5 100644
--- a/media/libaudioclient/aidl/fuzzer/Android.bp
+++ b/media/libaudioclient/aidl/fuzzer/Android.bp
@@ -22,7 +22,7 @@
name: "libaudioclient_aidl_fuzzer_defaults",
static_libs: [
"android.hardware.audio.common@7.0-enums",
- "audiopermissioncontroller",
+ "libaudiopermission",
"libaudiomockhal",
"libfakeservicemanager",
"libjsoncpp",
diff --git a/media/libaudioclient/include/media/PolicyAidlConversion.h b/media/libaudioclient/include/media/PolicyAidlConversion.h
index 1b90d6b..ed9ddd6 100644
--- a/media/libaudioclient/include/media/PolicyAidlConversion.h
+++ b/media/libaudioclient/include/media/PolicyAidlConversion.h
@@ -28,6 +28,8 @@
#include <android/media/AudioMixRouteFlag.h>
#include <android/media/AudioMixType.h>
#include <android/media/AudioOffloadMode.h>
+#include <android/media/AudioPolicyForceUse.h>
+#include <android/media/AudioPolicyForcedConfig.h>
#include <android/media/DeviceRole.h>
#include <media/AidlConversionUtil.h>
@@ -82,6 +84,16 @@
ConversionResult<media::AudioPolicyDeviceState>
legacy2aidl_audio_policy_dev_state_t_AudioPolicyDeviceState(audio_policy_dev_state_t legacy);
+ConversionResult<audio_policy_force_use_t>
+aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t(media::AudioPolicyForceUse aidl);
+ConversionResult<media::AudioPolicyForceUse>
+legacy2aidl_audio_policy_force_use_t_AudioPolicyForceUse(audio_policy_force_use_t legacy);
+
+ConversionResult<audio_policy_forced_cfg_t>
+aidl2legacy_AudioPolicyForcedConfig_audio_policy_forced_cfg_t(media::AudioPolicyForcedConfig aidl);
+ConversionResult<media::AudioPolicyForcedConfig>
+legacy2aidl_audio_policy_forced_cfg_t_AudioPolicyForcedConfig(audio_policy_forced_cfg_t legacy);
+
ConversionResult<device_role_t>
aidl2legacy_DeviceRole_device_role_t(media::DeviceRole aidl);
ConversionResult<media::DeviceRole>
diff --git a/services/audiopolicy/permission/Android.bp b/media/libaudiopermission/Android.bp
similarity index 87%
rename from services/audiopolicy/permission/Android.bp
rename to media/libaudiopermission/Android.bp
index cfbeaae..161e5a7 100644
--- a/services/audiopolicy/permission/Android.bp
+++ b/media/libaudiopermission/Android.bp
@@ -4,13 +4,13 @@
}
cc_library_headers {
- name: "audiopermissioncontroller_headers",
+ name: "libaudiopermission_headers",
host_supported: true,
export_include_dirs: ["include"],
}
cc_library {
- name: "audiopermissioncontroller",
+ name: "libaudiopermission",
srcs: [
"NativePermissionController.cpp",
@@ -83,14 +83,14 @@
}
cc_test {
- name: "audiopermissioncontroller_test",
+ name: "libaudiopermission_tests",
host_supported: true,
defaults: [
"libmediautils_tests_config",
],
static_libs: [
"audio-permission-aidl-cpp",
- "audiopermissioncontroller",
+ "libaudiopermission",
"framework-permission-aidl-cpp",
"libgmock",
],
@@ -100,10 +100,7 @@
"liblog",
"libutils",
],
- srcs: [
- "tests/NativePermissionControllerTest.cpp",
- "tests/ValidatedAttributionSourceStateTest.cpp",
- ],
+ srcs: ["tests/*.cpp"],
test_options: {
unit_test: true,
},
diff --git a/services/audiopolicy/permission/NativePermissionController.cpp b/media/libaudiopermission/NativePermissionController.cpp
similarity index 100%
rename from services/audiopolicy/permission/NativePermissionController.cpp
rename to media/libaudiopermission/NativePermissionController.cpp
diff --git a/services/audiopolicy/permission/ValidatedAttributionSourceState.cpp b/media/libaudiopermission/ValidatedAttributionSourceState.cpp
similarity index 100%
rename from services/audiopolicy/permission/ValidatedAttributionSourceState.cpp
rename to media/libaudiopermission/ValidatedAttributionSourceState.cpp
diff --git a/media/libaudiopermission/include/media/AttrSourceIter.h b/media/libaudiopermission/include/media/AttrSourceIter.h
new file mode 100644
index 0000000..609d218
--- /dev/null
+++ b/media/libaudiopermission/include/media/AttrSourceIter.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <android/content/AttributionSourceState.h>
+
+#include <iterator>
+
+// AttributionSourceState are essentially an intrusive linked list, where the next field carries
+// the pointer to the next element. These iterator helpers allow for convenient iteration over the
+// entire attribution chain. Usage:
+// std::for_each(AttrSourceIter::begin(mAttributionSourceState), AttrSourceIter::end(), ...)
+namespace android::media::permission::AttrSourceIter {
+
+class ConstIter {
+ public:
+ using iterator_category = std::forward_iterator_tag;
+ using difference_type = std::ptrdiff_t;
+ using value_type = ::android::content::AttributionSourceState;
+ using pointer = const value_type*;
+ using reference = const value_type&;
+
+ ConstIter(const ::android::content::AttributionSourceState* attr) : mAttr(attr) {}
+
+ reference operator*() const { return *mAttr; }
+ pointer operator->() const { return mAttr; }
+
+ ConstIter& operator++() {
+ mAttr = !mAttr->next.empty() ? mAttr->next.data() : nullptr;
+ return *this;
+ }
+ ConstIter operator++(int) {
+ ConstIter tmp = *this;
+ ++(*this);
+ return tmp;
+ }
+
+ friend bool operator==(const ConstIter& a, const ConstIter& b) = default;
+
+ static ConstIter end() { return ConstIter(nullptr); }
+
+ private:
+ const ::android::content::AttributionSourceState* mAttr;
+};
+
+/**
+ * Non-const iterator. Note, AttributionSourceState is conceptually a linked list on the next field.
+ * Be very careful if `next` is modified over iteration, as it can go wrong easily.
+ */
+class Iter {
+ public:
+ using iterator_category = std::forward_iterator_tag;
+ using difference_type = std::ptrdiff_t;
+ using value_type = ::android::content::AttributionSourceState;
+ using pointer = value_type*;
+ using reference = value_type&;
+
+ Iter(::android::content::AttributionSourceState* attr) : mAttr(attr) {}
+
+ reference operator*() const { return *mAttr; }
+ pointer operator->() const { return mAttr; }
+
+ Iter& operator++() {
+ mAttr = !mAttr->next.empty() ? mAttr->next.data() : nullptr;
+ return *this;
+ }
+ Iter operator++(int) {
+ Iter tmp = *this;
+ ++(*this);
+ return tmp;
+ }
+
+ friend bool operator==(const Iter& a, const Iter& b) = default;
+
+ operator ConstIter() const { return ConstIter(mAttr); }
+
+ static Iter end() { return Iter(nullptr); }
+
+ private:
+ ::android::content::AttributionSourceState* mAttr;
+};
+
+inline Iter begin(::android::content::AttributionSourceState& a) {
+ return Iter(&a);
+}
+inline Iter end() {
+ return Iter::end();
+}
+inline ConstIter cbegin(const ::android::content::AttributionSourceState& a) {
+ return ConstIter(&a);
+}
+inline ConstIter cend() {
+ return ConstIter::end();
+}
+} // namespace com::android::media::permission::AttrSourceIter
diff --git a/services/audiopolicy/permission/include/media/IPermissionProvider.h b/media/libaudiopermission/include/media/IPermissionProvider.h
similarity index 100%
rename from services/audiopolicy/permission/include/media/IPermissionProvider.h
rename to media/libaudiopermission/include/media/IPermissionProvider.h
diff --git a/services/audiopolicy/permission/include/media/NativePermissionController.h b/media/libaudiopermission/include/media/NativePermissionController.h
similarity index 100%
rename from services/audiopolicy/permission/include/media/NativePermissionController.h
rename to media/libaudiopermission/include/media/NativePermissionController.h
diff --git a/services/audiopolicy/permission/include/media/ValidatedAttributionSourceState.h b/media/libaudiopermission/include/media/ValidatedAttributionSourceState.h
similarity index 100%
rename from services/audiopolicy/permission/include/media/ValidatedAttributionSourceState.h
rename to media/libaudiopermission/include/media/ValidatedAttributionSourceState.h
diff --git a/media/libaudiopermission/tests/AttrSourceIterTests.cpp b/media/libaudiopermission/tests/AttrSourceIterTests.cpp
new file mode 100644
index 0000000..57d326d
--- /dev/null
+++ b/media/libaudiopermission/tests/AttrSourceIterTests.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/content/AttributionSourceState.h>
+#include <media/AttrSourceIter.h>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <algorithm>
+
+using ::android::content::AttributionSourceState;
+using ::android::media::permission::AttrSourceIter::begin;
+using ::android::media::permission::AttrSourceIter::cbegin;
+using ::android::media::permission::AttrSourceIter::cend;
+using ::android::media::permission::AttrSourceIter::end;
+
+using ::android::media::permission::AttrSourceIter::ConstIter;
+
+using ::testing::ContainerEq;
+using ::testing::ElementsAreArray;
+using ::testing::Eq;
+using ::testing::Return;
+
+class AttrSourceIterTest : public ::testing::Test {
+ public:
+ AttrSourceIterTest() {
+ mAttr.pid = 1;
+ mAttr.uid = 1;
+ AttributionSourceState next;
+ next.pid = 2;
+ next.uid = 2;
+ AttributionSourceState nextnext;
+ nextnext.pid = 3;
+ nextnext.uid = 3;
+ next.next = {nextnext};
+ mAttr.next = {next};
+ }
+
+ protected:
+ AttributionSourceState mAttr;
+};
+
+TEST_F(AttrSourceIterTest, constIter) {
+ const AttributionSourceState& ref = mAttr;
+ std::vector<int> mPids;
+ std::transform(cbegin(ref), cend(), std::back_inserter(mPids),
+ [](const auto& x) { return x.pid; });
+ EXPECT_THAT(mPids, ElementsAreArray({1, 2, 3}));
+}
+
+TEST_F(AttrSourceIterTest, nonConstIter) {
+ AttributionSourceState expected;
+ {
+ expected.pid = 2;
+ expected.uid = 1;
+ AttributionSourceState expectedNext;
+ expectedNext.pid = 4;
+ expectedNext.uid = 2;
+ AttributionSourceState expectedNextNext;
+ expectedNextNext.pid = 6;
+ expectedNextNext.uid = 3;
+ expectedNext.next = {expectedNextNext};
+ expected.next = {expectedNext};
+ }
+ std::for_each(begin(mAttr), end(), [](auto& x) { x.pid = x.pid * 2; });
+
+ EXPECT_THAT(mAttr, Eq(expected));
+}
+
+TEST_F(AttrSourceIterTest, nonConstIterReferenceEquals) {
+ const AttributionSourceState& ref = mAttr;
+ std::vector<const AttributionSourceState*> attrs;
+ std::transform(cbegin(ref), cend(), std::back_inserter(attrs),
+ [](const auto& x) { return &x; });
+ std::for_each(begin(mAttr), end(), [](auto& x) { x.pid = x.pid * 2; });
+ std::vector<const AttributionSourceState*> attrsAfter;
+ std::transform(cbegin(ref), cend(), std::back_inserter(attrsAfter),
+ [](const auto& x) { return &x; });
+ EXPECT_THAT(attrs, ContainerEq(attrsAfter));
+}
diff --git a/services/audiopolicy/permission/tests/NativePermissionControllerTest.cpp b/media/libaudiopermission/tests/NativePermissionControllerTest.cpp
similarity index 100%
rename from services/audiopolicy/permission/tests/NativePermissionControllerTest.cpp
rename to media/libaudiopermission/tests/NativePermissionControllerTest.cpp
diff --git a/services/audiopolicy/permission/tests/ValidatedAttributionSourceStateTest.cpp b/media/libaudiopermission/tests/ValidatedAttributionSourceStateTest.cpp
similarity index 100%
rename from services/audiopolicy/permission/tests/ValidatedAttributionSourceStateTest.cpp
rename to media/libaudiopermission/tests/ValidatedAttributionSourceStateTest.cpp
diff --git a/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp b/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
index 53d4311..5574ea1 100644
--- a/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
+++ b/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
@@ -93,7 +93,18 @@
RetCode BundleContext::setCommon(const Parameter::Common& common) {
RetCode ret = EffectContext::setCommon(common);
RETURN_VALUE_IF(ret != RetCode::SUCCESS, ret, " setCommonFailed");
- return init();
+ if (mInstance) {
+ LVM_ControlParams_t params;
+ RETURN_VALUE_IF(LVM_SUCCESS != LVM_GetControlParameters(mInstance, ¶ms),
+ RetCode::ERROR_EFFECT_LIB_ERROR, "failGetControlParams");
+ RETURN_VALUE_IF(RetCode::SUCCESS != applyCommonParameter(params),
+ RetCode::ERROR_EFFECT_LIB_ERROR, " applyCommonParameterFailed");
+ RETURN_VALUE_IF(LVM_SUCCESS != LVM_SetControlParameters(mInstance, ¶ms),
+ RetCode::ERROR_EFFECT_LIB_ERROR, "failSetControlParams");
+ } else {
+ RETURN_VALUE_IF(RetCode::SUCCESS != init(), RetCode::ERROR_EFFECT_LIB_ERROR, " initFailed");
+ }
+ return RetCode::SUCCESS;
}
RetCode BundleContext::enable() {
@@ -605,7 +616,7 @@
return ret;
}
-RetCode BundleContext::initControlParameter(LVM_ControlParams_t& params) const {
+RetCode BundleContext::applyCommonParameter(LVM_ControlParams_t& params) const {
int outputChannelCount = ::aidl::android::hardware::audio::common::getChannelCount(
mCommon.output.base.channelMask);
auto outputChannelMaskConv = aidl2legacy_AudioChannelLayout_audio_channel_mask_t(
@@ -627,6 +638,13 @@
params.SourceFormat = LVM_MULTICHANNEL;
}
+ return RetCode::SUCCESS;
+}
+
+RetCode BundleContext::initControlParameter(LVM_ControlParams_t& params) const {
+ RETURN_VALUE_IF(RetCode::SUCCESS != applyCommonParameter(params),
+ RetCode::ERROR_EFFECT_LIB_ERROR, " applyCommonParameterFailed");
+
/* General parameters */
params.OperatingMode = LVM_MODE_ON;
params.SpeakerType = LVM_HEADPHONES;
diff --git a/media/libeffects/lvm/wrapper/Aidl/BundleContext.h b/media/libeffects/lvm/wrapper/Aidl/BundleContext.h
index d5de5bd..96f63cd 100644
--- a/media/libeffects/lvm/wrapper/Aidl/BundleContext.h
+++ b/media/libeffects/lvm/wrapper/Aidl/BundleContext.h
@@ -135,6 +135,7 @@
bool isBandLevelIndexInRange(const std::vector<Equalizer::BandLevel>& bandLevels) const;
static LVM_EQNB_BandDef_t* getDefaultEqualizerBandDefs();
static LVM_HeadroomBandDef_t* getDefaultEqualizerHeadroomBanDefs();
+ RetCode applyCommonParameter(LVM_ControlParams_t& params) const;
};
} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 83a2b68..894c459 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -260,6 +260,7 @@
srcs: [
"AudioCapabilities.cpp",
"CodecCapabilities.cpp",
+ "EncoderCapabilities.cpp",
"VideoCapabilities.cpp",
"CodecCapabilitiesUtils.cpp",
],
diff --git a/media/libmedia/CodecCapabilities.cpp b/media/libmedia/CodecCapabilities.cpp
index 87eb4bc..407d376 100644
--- a/media/libmedia/CodecCapabilities.cpp
+++ b/media/libmedia/CodecCapabilities.cpp
@@ -17,6 +17,7 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "CodecCapabilities"
+#include <android-base/strings.h>
#include <utils/Log.h>
#include <media/CodecCapabilities.h>
#include <media/CodecCapabilitiesUtils.h>
@@ -25,6 +26,58 @@
namespace android {
+static const int32_t HEVCHighTierLevels =
+ HEVCHighTierLevel1 | HEVCHighTierLevel2 | HEVCHighTierLevel21 | HEVCHighTierLevel3 |
+ HEVCHighTierLevel31 | HEVCHighTierLevel4 | HEVCHighTierLevel41 | HEVCHighTierLevel5 |
+ HEVCHighTierLevel51 | HEVCHighTierLevel52 | HEVCHighTierLevel6 | HEVCHighTierLevel61 |
+ HEVCHighTierLevel62;
+
+static const int32_t DEFAULT_MAX_SUPPORTED_INSTANCES = 32;
+static const int32_t MAX_SUPPORTED_INSTANCES_LIMIT = 256;
+
+// must not contain KEY_PROFILE
+static const std::set<std::pair<std::string, AMessage::Type>> AUDIO_LEVEL_CRITICAL_FORMAT_KEYS = {
+ // We don't set level-specific limits for audio codecs today. Key candidates would
+ // be sample rate, bit rate or channel count.
+ // MediaFormat.KEY_SAMPLE_RATE,
+ // MediaFormat.KEY_CHANNEL_COUNT,
+ // MediaFormat.KEY_BIT_RATE,
+ { KEY_MIME, AMessage::kTypeString }
+};
+
+// CodecCapabilities Features
+static const std::vector<Feature> DECODER_FEATURES = {
+ Feature(FEATURE_AdaptivePlayback, (1 << 0), true),
+ Feature(FEATURE_SecurePlayback, (1 << 1), false),
+ Feature(FEATURE_TunneledPlayback, (1 << 2), false),
+ Feature(FEATURE_PartialFrame, (1 << 3), false),
+ Feature(FEATURE_FrameParsing, (1 << 4), false),
+ Feature(FEATURE_MultipleFrames, (1 << 5), false),
+ Feature(FEATURE_DynamicTimestamp, (1 << 6), false),
+ Feature(FEATURE_LowLatency, (1 << 7), true),
+ // feature to exclude codec from REGULAR codec list
+ Feature(FEATURE_SpecialCodec, (1 << 30), false, true),
+};
+static const std::vector<Feature> ENCODER_FEATURES = {
+ Feature(FEATURE_IntraRefresh, (1 << 0), false),
+ Feature(FEATURE_MultipleFrames, (1 << 1), false),
+ Feature(FEATURE_DynamicTimestamp, (1 << 2), false),
+ Feature(FEATURE_QpBounds, (1 << 3), false),
+ Feature(FEATURE_EncodingStatistics, (1 << 4), false),
+ Feature(FEATURE_HdrEditing, (1 << 5), false),
+ // feature to exclude codec from REGULAR codec list
+ Feature(FEATURE_SpecialCodec, (1 << 30), false, true),
+};
+
+// must not contain KEY_PROFILE
+static const std::set<std::pair<std::string, AMessage::Type>> VIDEO_LEVEL_CRITICAL_FORMAT_KEYS = {
+ { KEY_WIDTH, AMessage::kTypeInt32 },
+ { KEY_HEIGHT, AMessage::kTypeInt32 },
+ { KEY_FRAME_RATE, AMessage::kTypeInt32 },
+ { KEY_BIT_RATE, AMessage::kTypeInt32 },
+ { KEY_MIME, AMessage::kTypeString }
+};
+
bool CodecCapabilities::SupportsBitrate(Range<int32_t> bitrateRange,
const sp<AMessage> &format) {
// consider max bitrate over average bitrate for support
@@ -46,6 +99,212 @@
return true;
}
+bool CodecCapabilities::isFeatureSupported(const std::string &name) const {
+ return mFeaturesSupported.contains(name);
+}
+
+bool CodecCapabilities::isFeatureRequired(const std::string &name) const {
+ return mFeaturesRequired.contains(name);
+}
+
+std::vector<std::string> CodecCapabilities::validFeatures() const {
+ std::vector<std::string> res;
+ for (const Feature& feature : getValidFeatures()) {
+ if (!feature.mInternal) {
+ res.push_back(feature.mName);
+ }
+ }
+ return res;
+}
+
+std::vector<Feature> CodecCapabilities::getValidFeatures() const {
+ if (isEncoder()) {
+ return ENCODER_FEATURES;
+ } else {
+ return DECODER_FEATURES;
+ }
+}
+
+bool CodecCapabilities::isRegular() const {
+ // regular codecs only require default features
+ std::vector<Feature> features = getValidFeatures();
+ return std::all_of(features.begin(), features.end(),
+ [this](Feature feat){ return (feat.mDefault || !isFeatureRequired(feat.mName)); });
+}
+
+bool CodecCapabilities::isFormatSupported(const sp<AMessage> &format) const {
+ AString mediaType;
+ format->findString(KEY_MIME, &mediaType);
+ // mediaType must match if present
+ if (!base::EqualsIgnoreCase(mMediaType, mediaType.c_str())) {
+ return false;
+ }
+
+ // check feature support
+ for (Feature feat: getValidFeatures()) {
+ if (feat.mInternal) {
+ continue;
+ }
+
+ int32_t yesNo;
+ std::string key = KEY_FEATURE_;
+ key = key + feat.mName;
+ if (format->findInt32(key.c_str(), &yesNo)) {
+ continue;
+ }
+ if ((yesNo == 1 && !isFeatureSupported(feat.mName)) ||
+ (yesNo == 0 && isFeatureRequired(feat.mName))) {
+ return false;
+ }
+ }
+
+ int32_t profile;
+ if (format->findInt32(KEY_PROFILE, &profile)) {
+ int32_t level = -1;
+ format->findInt32(KEY_LEVEL, &level);
+ if (!supportsProfileLevel(profile, level)) {
+ return false;
+ }
+
+ // If we recognize this profile, check that this format is supported by the
+ // highest level supported by the codec for that profile. (Ignore specified
+ // level beyond the above profile/level check as level is only used as a
+ // guidance. E.g. AVC Level 1 CIF format is supported if codec supports level 1.1
+ // even though max size for Level 1 is QCIF. However, MPEG2 Simple Profile
+ // 1080p format is not supported even if codec supports Main Profile Level High,
+ // as Simple Profile does not support 1080p.
+ int32_t maxLevel = 0;
+ for (ProfileLevel pl : mProfileLevels) {
+ if (pl.mProfile == profile && pl.mLevel > maxLevel) {
+ // H.263 levels are not completely ordered:
+ // Level45 support only implies Level10 support
+ if (!base::EqualsIgnoreCase(mMediaType, MIMETYPE_VIDEO_H263)
+ || pl.mLevel != H263Level45
+ || maxLevel == H263Level10) {
+ maxLevel = pl.mLevel;
+ }
+ }
+ }
+ std::shared_ptr<CodecCapabilities> levelCaps
+ = CreateFromProfileLevel(mMediaType, profile, maxLevel);
+ // We must remove the profile from this format otherwise levelCaps.isFormatSupported
+ // will get into this same condition and loop forever. Furthermore, since levelCaps
+ // does not contain features and bitrate specific keys, keep only keys relevant for
+ // a level check.
+ sp<AMessage> levelCriticalFormat = new AMessage;
+
+ // critical keys will always contain KEY_MIME, but should also contain others to be
+ // meaningful
+ if ((isVideo() || isAudio()) && levelCaps != nullptr) {
+ const std::set<std::pair<std::string, AMessage::Type>> criticalKeys =
+ isVideo() ? VIDEO_LEVEL_CRITICAL_FORMAT_KEYS : AUDIO_LEVEL_CRITICAL_FORMAT_KEYS;
+ for (std::pair<std::string, AMessage::Type> key : criticalKeys) {
+ if (format->contains(key.first.c_str())) {
+ // AMessage::ItemData value = format->findItem(key.c_str());
+ // levelCriticalFormat->setItem(key.c_str(), value);
+ switch (key.second) {
+ case AMessage::kTypeInt32: {
+ int32_t value;
+ format->findInt32(key.first.c_str(), &value);
+ levelCriticalFormat->setInt32(key.first.c_str(), value);
+ break;
+ }
+ case AMessage::kTypeString: {
+ AString value;
+ format->findString(key.first.c_str(), &value);
+ levelCriticalFormat->setString(key.first.c_str(), value);
+ break;
+ }
+ default:
+ ALOGE("Unsupported type");
+ }
+ }
+ }
+ if (!levelCaps->isFormatSupported(levelCriticalFormat)) {
+ return false;
+ }
+ }
+ }
+ if (mAudioCaps && !mAudioCaps->supportsFormat(format)) {
+ return false;
+ }
+ if (mVideoCaps && !mVideoCaps->supportsFormat(format)) {
+ return false;
+ }
+ if (mEncoderCaps && !mEncoderCaps->supportsFormat(format)) {
+ return false;
+ }
+ return true;
+}
+
+bool CodecCapabilities::supportsProfileLevel(int32_t profile, int32_t level) const {
+ for (ProfileLevel pl: mProfileLevels) {
+ if (pl.mProfile != profile) {
+ continue;
+ }
+
+ // No specific level requested
+ if (level == -1) {
+ return true;
+ }
+
+ // AAC doesn't use levels
+ if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AAC)) {
+ return true;
+ }
+
+ // DTS doesn't use levels
+ if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_DTS)
+ || base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_DTS_HD)
+ || base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_DTS_UHD)) {
+ return true;
+ }
+
+ // H.263 levels are not completely ordered:
+ // Level45 support only implies Level10 support
+ if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_VIDEO_H263)) {
+ if (pl.mLevel != level && pl.mLevel == H263Level45
+ && level > H263Level10) {
+ continue;
+ }
+ }
+
+ // MPEG4 levels are not completely ordered:
+ // Level1 support only implies Level0 (and not Level0b) support
+ if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_VIDEO_MPEG4)) {
+ if (pl.mLevel != level && pl.mLevel == MPEG4Level1
+ && level > MPEG4Level0) {
+ continue;
+ }
+ }
+
+ // HEVC levels incorporate both tiers and levels. Verify tier support.
+ if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_VIDEO_HEVC)) {
+ bool supportsHighTier =
+ (pl.mLevel & HEVCHighTierLevels) != 0;
+ bool checkingHighTier = (level & HEVCHighTierLevels) != 0;
+ // high tier levels are only supported by other high tier levels
+ if (checkingHighTier && !supportsHighTier) {
+ continue;
+ }
+ }
+
+ if (pl.mLevel >= level) {
+ // if we recognize the listed profile/level, we must also recognize the
+ // profile/level arguments.
+ if (CreateFromProfileLevel(mMediaType, profile, pl.mLevel) != nullptr) {
+ return CreateFromProfileLevel(mMediaType, profile, level) != nullptr;
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+sp<AMessage> CodecCapabilities::getDefaultFormat() const {
+ return mDefaultFormat;
+}
+
const std::string& CodecCapabilities::getMediaType() {
return mMediaType;
}
@@ -54,4 +313,130 @@
return mProfileLevels;
}
+std::vector<uint32_t> CodecCapabilities::getColorFormats() const {
+ return mColorFormats;
+}
+
+int32_t CodecCapabilities::getMaxSupportedInstances() const {
+ return mMaxSupportedInstances;
+}
+
+bool CodecCapabilities::isAudio() const {
+ return mAudioCaps != nullptr;
+}
+
+std::shared_ptr<AudioCapabilities>
+ CodecCapabilities::getAudioCapabilities() const {
+ return mAudioCaps;
+}
+
+bool CodecCapabilities::isEncoder() const {
+ return mEncoderCaps != nullptr;
+}
+
+std::shared_ptr<EncoderCapabilities>
+ CodecCapabilities::getEncoderCapabilities() const {
+ return mEncoderCaps;
+}
+
+bool CodecCapabilities::isVideo() const {
+ return mVideoCaps != nullptr;
+}
+
+std::shared_ptr<VideoCapabilities> CodecCapabilities::getVideoCapabilities() const {
+ return mVideoCaps;
+}
+
+// static
+std::shared_ptr<CodecCapabilities> CodecCapabilities::CreateFromProfileLevel(
+ std::string mediaType, int32_t profile, int32_t level, int32_t maxConcurrentInstances) {
+ ProfileLevel pl;
+ pl.mProfile = profile;
+ pl.mLevel = level;
+ sp<AMessage> defaultFormat = new AMessage;
+ defaultFormat->setString(KEY_MIME, mediaType.c_str());
+
+ std::vector<ProfileLevel> pls;
+ pls.push_back(pl);
+ std::vector<uint32_t> colFmts;
+ sp<AMessage> capabilitiesInfo = new AMessage;
+ std::shared_ptr<CodecCapabilities> ret(new CodecCapabilities());
+ ret->init(pls, colFmts, true /* encoder */, defaultFormat, capabilitiesInfo,
+ maxConcurrentInstances);
+ if (ret->getErrors() != 0) {
+ return nullptr;
+ }
+ return ret;
+}
+
+void CodecCapabilities::init(std::vector<ProfileLevel> profLevs, std::vector<uint32_t> colFmts,
+ bool encoder, sp<AMessage> &defaultFormat, sp<AMessage> &capabilitiesInfo,
+ int32_t maxConcurrentInstances) {
+ mColorFormats = colFmts;
+ mDefaultFormat = defaultFormat;
+ mCapabilitiesInfo = capabilitiesInfo;
+
+ AString mediaTypeAStr;
+ mDefaultFormat->findString(KEY_MIME, &mediaTypeAStr);
+ mMediaType = mediaTypeAStr.c_str();
+
+ /* VP9 introduced profiles around 2016, so some VP9 codecs may not advertise any
+ supported profiles. Determine the level for them using the info they provide. */
+ if (profLevs.size() == 0 && mMediaType == MIMETYPE_VIDEO_VP9) {
+ ProfileLevel profLev;
+ profLev.mProfile = VP9Profile0;
+ profLev.mLevel = VideoCapabilities::EquivalentVP9Level(capabilitiesInfo);
+ profLevs.push_back(profLev);
+ }
+ mProfileLevels = profLevs;
+
+ if (mediaTypeAStr.startsWithIgnoreCase("audio/")) {
+ mAudioCaps = AudioCapabilities::Create(mMediaType, profLevs, capabilitiesInfo);
+ mAudioCaps->getDefaultFormat(mDefaultFormat);
+ } else if (mediaTypeAStr.startsWithIgnoreCase("video/")
+ || mediaTypeAStr.equalsIgnoreCase(MIMETYPE_IMAGE_ANDROID_HEIC)) {
+ mVideoCaps = VideoCapabilities::Create(mMediaType, profLevs, capabilitiesInfo);
+ }
+
+ if (encoder) {
+ mEncoderCaps = EncoderCapabilities::Create(mMediaType, profLevs, capabilitiesInfo);
+ mEncoderCaps->getDefaultFormat(mDefaultFormat);
+ }
+
+ mMaxSupportedInstances = maxConcurrentInstances > 0
+ ? maxConcurrentInstances : DEFAULT_MAX_SUPPORTED_INSTANCES;
+
+ int32_t maxInstances = mMaxSupportedInstances;
+ capabilitiesInfo->findInt32("max-concurrent-instances", &maxInstances);
+ mMaxSupportedInstances =
+ Range(1, MAX_SUPPORTED_INSTANCES_LIMIT).clamp(maxInstances);
+
+ mFeaturesRequired.clear();
+ mFeaturesSupported.clear();
+ for (Feature feat: getValidFeatures()) {
+ std::string key = KEY_FEATURE_;
+ key = key + feat.mName;
+ int yesNo = -1;
+ if (!capabilitiesInfo->findInt32(key.c_str(), &yesNo)) {
+ continue;
+ }
+ if (yesNo > 0) {
+ mFeaturesRequired.insert(feat.mName);
+ }
+ mFeaturesSupported.insert(feat.mName);
+ if (!feat.mInternal) {
+ mDefaultFormat->setInt32(key.c_str(), 1);
+ }
+ }
+}
+
+int32_t CodecCapabilities::getErrors() const {
+ if (mAudioCaps) {
+ return mAudioCaps->mError;
+ } else if (mVideoCaps) {
+ return mVideoCaps->mError;
+ }
+ return 0;
+}
+
} // namespace android
\ No newline at end of file
diff --git a/media/libmedia/EncoderCapabilities.cpp b/media/libmedia/EncoderCapabilities.cpp
new file mode 100644
index 0000000..a840220
--- /dev/null
+++ b/media/libmedia/EncoderCapabilities.cpp
@@ -0,0 +1,205 @@
+/*
+ * Copyright 2024, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "EncoderCapabilities"
+
+#include <android-base/strings.h>
+
+#include <media/CodecCapabilities.h>
+#include <media/EncoderCapabilities.h>
+#include <media/stagefright/MediaCodecConstants.h>
+
+namespace android {
+
+const Range<int>& EncoderCapabilities::getQualityRange() {
+ return mQualityRange;
+}
+
+const Range<int>& EncoderCapabilities::getComplexityRange() {
+ return mComplexityRange;
+}
+
+// static
+int EncoderCapabilities::ParseBitrateMode(std::string mode) {
+ for (Feature feat: sBitrateModes) {
+ if (base::EqualsIgnoreCase(feat.mName, mode)) {
+ return feat.mValue;
+ }
+ }
+ return 0;
+}
+
+bool EncoderCapabilities::isBitrateModeSupported(int mode) {
+ for (Feature feat : sBitrateModes) {
+ if (mode == feat.mValue) {
+ return (mBitControl & (1 << mode)) != 0;
+ }
+ }
+ return false;
+}
+
+// static
+std::shared_ptr<EncoderCapabilities> EncoderCapabilities::Create(std::string mediaType,
+ std::vector<ProfileLevel> profLevs, const sp<AMessage> &format) {
+ std::shared_ptr<EncoderCapabilities> caps(new EncoderCapabilities());
+ caps->init(mediaType, profLevs, format);
+ return caps;
+}
+
+void EncoderCapabilities::init(std::string mediaType, std::vector<ProfileLevel> profLevs,
+ const sp<AMessage> &format) {
+ // no support for complexity or quality yet
+ mMediaType = mediaType;
+ mProfileLevels = profLevs;
+ mComplexityRange = Range(0, 0);
+ mQualityRange = Range(0, 0);
+ mBitControl = (1 << BITRATE_MODE_VBR);
+
+ applyLevelLimits();
+ parseFromInfo(format);
+}
+
+void EncoderCapabilities::applyLevelLimits() {
+ if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_FLAC)) {
+ mComplexityRange = Range(0, 8);
+ mBitControl = (1 << BITRATE_MODE_CQ);
+ } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AMR_NB)
+ || base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AMR_WB)
+ || base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_G711_ALAW)
+ || base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_G711_MLAW)
+ || base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_MSGSM)) {
+ mBitControl = (1 << BITRATE_MODE_CBR);
+ }
+}
+
+void EncoderCapabilities::parseFromInfo(const sp<AMessage> &format) {
+ AString complexityRangeAStr;
+ if (format->findString("complexity-range", &complexityRangeAStr)) {
+ std::optional<Range<int>> complexityRangeOpt
+ = Range<int32_t>::Parse(std::string(complexityRangeAStr.c_str()));
+ mComplexityRange = complexityRangeOpt.value_or(mComplexityRange);
+ // TODO should we limit this to level limits?
+ }
+ AString qualityRangeAStr;
+ if (format->findString("quality-range", &qualityRangeAStr)) {
+ std::optional<Range<int>> qualityRangeOpt
+ = Range<int32_t>::Parse(std::string(qualityRangeAStr.c_str()));
+ mQualityRange = qualityRangeOpt.value_or(mQualityRange);
+ }
+ AString bitrateModesAStr;
+ if (format->findString("feature-bitrate-modes", &bitrateModesAStr)) {
+ mBitControl = 0;
+ for (std::string mode: base::Split(std::string(bitrateModesAStr.c_str()), ",")) {
+ mBitControl |= (1 << ParseBitrateMode(mode));
+ }
+ }
+ format->findInt32("complexity-default", &mDefaultComplexity);
+ format->findInt32("quality-default", &mDefaultQuality);
+ AString qualityScaleAStr;
+ if (format->findString("quality-scale", &qualityScaleAStr)) {
+ mQualityScale = std::string(qualityScaleAStr.c_str());
+ }
+}
+
+bool EncoderCapabilities::supports(
+ std::optional<int> complexity, std::optional<int> quality, std::optional<int> profile) {
+ bool ok = true;
+ if (complexity) {
+ ok &= mComplexityRange.contains(complexity.value());
+ }
+ if (quality) {
+ ok &= mQualityRange.contains(quality.value());
+ }
+ if (profile) {
+ ok &= std::any_of(mProfileLevels.begin(), mProfileLevels.end(),
+ [&profile](ProfileLevel pl){ return pl.mProfile == profile.value(); });
+ }
+ return ok;
+}
+
+void EncoderCapabilities::getDefaultFormat(sp<AMessage> &format) {
+ // don't list trivial quality/complexity as default for now
+ if (mQualityRange.upper() != mQualityRange.lower()
+ && mDefaultQuality != 0) {
+ format->setInt32(KEY_QUALITY, mDefaultQuality);
+ }
+ if (mComplexityRange.upper() != mComplexityRange.lower()
+ && mDefaultComplexity != 0) {
+ format->setInt32(KEY_COMPLEXITY, mDefaultComplexity);
+ }
+ // bitrates are listed in order of preference
+ for (Feature feat : sBitrateModes) {
+ if ((mBitControl & (1 << feat.mValue)) != 0) {
+ format->setInt32(KEY_BITRATE_MODE, feat.mValue);
+ break;
+ }
+ }
+}
+
+bool EncoderCapabilities::supportsFormat(const sp<AMessage> &format) {
+ int32_t mode;
+ if (format->findInt32(KEY_BITRATE_MODE, &mode) && !isBitrateModeSupported(mode)) {
+ return false;
+ }
+
+ int tmp;
+ std::optional<int> complexity = std::nullopt;
+ if (format->findInt32(KEY_COMPLEXITY, &tmp)) {
+ complexity = tmp;
+ }
+
+ if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_FLAC)) {
+ int flacComplexity;
+ if (format->findInt32(KEY_FLAC_COMPRESSION_LEVEL, &flacComplexity)) {
+ if (!complexity) {
+ complexity = flacComplexity;
+ } else if (flacComplexity != complexity.value()) {
+ ALOGE("Conflicting values for complexity and flac-compression-level,"
+ " which are %d and %d", complexity.value(), flacComplexity);
+ return false;
+ }
+ }
+ }
+
+ // other audio parameters
+ std::optional<int> profile = std::nullopt;
+ if (format->findInt32(KEY_PROFILE, &tmp)) {
+ profile = tmp;
+ }
+
+ if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AAC)) {
+ int aacProfile;
+ if (format->findInt32(KEY_AAC_PROFILE, &aacProfile)) {
+ if (!profile) {
+ profile = aacProfile;
+ } else if (aacProfile != profile.value()) {
+ ALOGE("Conflicting values for profile and aac-profile, which are %d and %d",
+ profile.value(), aacProfile);
+ return false;
+ }
+ }
+ }
+
+ std::optional<int> quality = std::nullopt;
+ if (format->findInt32(KEY_QUALITY, &tmp)) {
+ quality = tmp;
+ }
+
+ return supports(complexity, quality, profile);
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/media/libmedia/MediaCodecInfo.cpp b/media/libmedia/MediaCodecInfo.cpp
index d5d1a09..3834278 100644
--- a/media/libmedia/MediaCodecInfo.cpp
+++ b/media/libmedia/MediaCodecInfo.cpp
@@ -26,6 +26,9 @@
namespace android {
+// initialize max supported instances with default value.
+int32_t MediaCodecInfo::sMaxSupportedInstances = 0;
+
/** This redundant redeclaration is needed for C++ pre 14 */
constexpr char MediaCodecInfo::Capabilities::FEATURE_ADAPTIVE_PLAYBACK[];
constexpr char MediaCodecInfo::Capabilities::FEATURE_DYNAMIC_TIMESTAMP[];
@@ -169,6 +172,15 @@
return NULL;
}
+const std::shared_ptr<CodecCapabilities> MediaCodecInfo::getCodecCapsFor(
+ const char *mediaType) const {
+ ssize_t ix = getCodecCapIndex(mediaType);
+ if (ix >= 0) {
+ return mCodecCaps.valueAt(ix);
+ }
+ return nullptr;
+}
+
const char *MediaCodecInfo::getCodecName() const {
return mName.c_str();
}
@@ -179,6 +191,7 @@
// static
sp<MediaCodecInfo> MediaCodecInfo::FromParcel(const Parcel &parcel) {
+ sMaxSupportedInstances = parcel.readInt32();
AString name = AString::FromParcel(parcel);
AString owner = AString::FromParcel(parcel);
Attributes attributes = static_cast<Attributes>(parcel.readInt32());
@@ -201,12 +214,17 @@
return NULL;
if (info != NULL) {
info->mCaps.add(mediaType, caps);
+ std::shared_ptr<CodecCapabilities> codecCaps
+ = MediaCodecInfoWriter::BuildCodecCapabilities(
+ mediaType.c_str(), caps, info->isEncoder());
+ info->mCodecCaps.add(mediaType, codecCaps);
}
}
return info;
}
status_t MediaCodecInfo::writeToParcel(Parcel *parcel) const {
+ parcel->writeInt32(sMaxSupportedInstances);
mName.writeToParcel(parcel);
mOwner.writeToParcel(parcel);
parcel->writeInt32(mAttributes);
@@ -234,6 +252,25 @@
return -1;
}
+ssize_t MediaCodecInfo::getCodecCapIndex(const char *mediaType) const {
+ if (mediaType == nullptr) {
+ return -1;
+ }
+
+ if (mCodecCaps.size() != mCaps.size()) {
+ ALOGE("Size of mCodecCaps and mCaps do not match, which are %zu and %zu",
+ mCodecCaps.size(), mCaps.size());
+ }
+
+ for (size_t ix = 0; ix < mCodecCaps.size(); ix++) {
+ if (mCodecCaps.keyAt(ix).equalsIgnoreCase(mediaType)) {
+ return ix;
+ }
+ }
+
+ return -1;
+}
+
MediaCodecInfo::MediaCodecInfo()
: mAttributes((MediaCodecInfo::Attributes)0),
mRank(0x100) {
@@ -283,6 +320,52 @@
return false;
}
+void MediaCodecInfoWriter::createCodecCaps() {
+ mInfo->mCodecCaps.clear();
+ for (size_t ix = 0; ix < mInfo->mCaps.size(); ix++) {
+ AString mediaType = mInfo->mCaps.keyAt(ix);
+ sp<MediaCodecInfo::Capabilities> caps = mInfo->mCaps.valueAt(ix);
+ mInfo->mCodecCaps.add(mediaType,
+ BuildCodecCapabilities(mediaType.c_str(), caps, mInfo->isEncoder(),
+ MediaCodecInfo::sMaxSupportedInstances));
+ }
+}
+
+// static
+std::shared_ptr<CodecCapabilities> MediaCodecInfoWriter::BuildCodecCapabilities(
+ const char *mediaType, sp<MediaCodecInfo::Capabilities> caps, bool isEncoder,
+ int32_t maxSupportedInstances) {
+ Vector<ProfileLevel> profileLevels_;
+ Vector<uint32_t> colorFormats_;
+ caps->getSupportedProfileLevels(&profileLevels_);
+ caps->getSupportedColorFormats(&colorFormats_);
+
+ std::vector<ProfileLevel> profileLevels;
+ std::vector<uint32_t> colorFormats;
+ for (ProfileLevel pl : profileLevels_) {
+ profileLevels.push_back(pl);
+ }
+ for (uint32_t cf : colorFormats_) {
+ colorFormats.push_back(cf);
+ }
+
+ sp<AMessage> defaultFormat = new AMessage();
+ defaultFormat->setString("mime", mediaType);
+
+ sp<AMessage> capabilitiesInfo = caps->getDetails();
+
+ std::shared_ptr<CodecCapabilities> codecCaps = std::make_shared<CodecCapabilities>();
+ codecCaps->init(profileLevels, colorFormats, isEncoder, defaultFormat,
+ capabilitiesInfo, maxSupportedInstances);
+
+ return codecCaps;
+}
+
+// static
+void MediaCodecInfoWriter::SetMaxSupportedInstances(int32_t maxSupportedInstances) {
+ MediaCodecInfo::sMaxSupportedInstances = maxSupportedInstances;
+}
+
MediaCodecInfoWriter::MediaCodecInfoWriter(MediaCodecInfo* info) :
mInfo(info) {
}
diff --git a/media/libmedia/include/media/CodecCapabilities.h b/media/libmedia/include/media/CodecCapabilities.h
index 700373a..0611d8c 100644
--- a/media/libmedia/include/media/CodecCapabilities.h
+++ b/media/libmedia/include/media/CodecCapabilities.h
@@ -19,8 +19,9 @@
#define CODEC_CAPABILITIES_H_
#include <media/AudioCapabilities.h>
-#include <media/VideoCapabilities.h>
#include <media/CodecCapabilitiesUtils.h>
+#include <media/EncoderCapabilities.h>
+#include <media/VideoCapabilities.h>
#include <media/stagefright/foundation/ABase.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/AString.h>
@@ -39,6 +40,26 @@
const sp<AMessage> &format);
/**
+ * Retrieve the codec capabilities for a certain {@code mime type}, {@code
+ * profile} and {@code level}. If the type, or profile-level combination
+ * is not understood by the framework, it returns null.
+ * <p class=note> In {@link android.os.Build.VERSION_CODES#M}, calling this
+ * method without calling any method of the {@link MediaCodecList} class beforehand
+ * results in a {@link NullPointerException}.</p>
+ */
+ static std::shared_ptr<CodecCapabilities> CreateFromProfileLevel(std::string mediaType,
+ int32_t profile, int32_t level, int32_t maxConcurrentInstances = -1);
+
+ CodecCapabilities() {};
+
+ /**
+ * Init CodecCapabilities with settings.
+ */
+ void init(std::vector<ProfileLevel> profLevs, std::vector<uint32_t> colFmts, bool encoder,
+ sp<AMessage> &defaultFormat, sp<AMessage> &capabilitiesInfo,
+ int32_t maxConcurrentInstances = 0);
+
+ /**
* Returns the media type for which this codec-capability object was created.
*/
const std::string& getMediaType();
@@ -48,12 +69,209 @@
*/
const std::vector<ProfileLevel>& getProfileLevels();
+ /**
+ * Returns the supported color formats.
+ */
+ std::vector<uint32_t> getColorFormats() const;
+
+ /**
+ * Returns a media format with default values for configurations that have defaults.
+ */
+ sp<AMessage> getDefaultFormat() const;
+
+ /**
+ * Returns the max number of the supported concurrent codec instances.
+ * <p>
+ * This is a hint for an upper bound. Applications should not expect to successfully
+ * operate more instances than the returned value, but the actual number of
+ * concurrently operable instances may be less as it depends on the available
+ * resources at time of use.
+ */
+ int32_t getMaxSupportedInstances() const;
+
+ /**
+ * Returns the audio capabilities or {@code null} if this is not an audio codec.
+ */
+ std::shared_ptr<AudioCapabilities> getAudioCapabilities() const;
+
+ /**
+ * Returns the video capabilities or {@code null} if this is not a video codec.
+ */
+ std::shared_ptr<VideoCapabilities> getVideoCapabilities() const;
+
+ /**
+ * Returns the encoding capabilities or {@code null} if this is not an encoder.
+ */
+ std::shared_ptr<EncoderCapabilities> getEncoderCapabilities() const;
+
+ std::vector<std::string> validFeatures() const;
+
+ /**
+ * Query codec feature capabilities.
+ * <p>
+ * These features are supported to be used by the codec. These
+ * include optional features that can be turned on, as well as
+ * features that are always on.
+ */
+ bool isFeatureSupported(const std::string &name) const;
+
+ /**
+ * Query codec feature requirements.
+ * <p>
+ * These features are required to be used by the codec, and as such,
+ * they are always turned on.
+ */
+ bool isFeatureRequired(const std::string &name) const;
+
+ bool isRegular() const;
+
+ /**
+ * Query whether codec supports a given {@link MediaFormat}.
+ *
+ * <p class=note>
+ * <strong>Note:</strong> On {@link android.os.Build.VERSION_CODES#LOLLIPOP},
+ * {@code format} must not contain a {@linkplain MediaFormat#KEY_FRAME_RATE
+ * frame rate}. Use
+ * <code class=prettyprint>format.setString(MediaFormat.KEY_FRAME_RATE, null)</code>
+ * to clear any existing frame rate setting in the format.
+ * <p>
+ *
+ * The following table summarizes the format keys considered by this method.
+ * This is especially important to consider when targeting a higher SDK version than the
+ * minimum SDK version, as this method will disregard some keys on devices below the target
+ * SDK version.
+ *
+ * <table style="width: 0%">
+ * <thead>
+ * <tr>
+ * <th rowspan=3>OS Version(s)</th>
+ * <td colspan=3>{@code MediaFormat} keys considered for</th>
+ * </tr><tr>
+ * <th>Audio Codecs</th>
+ * <th>Video Codecs</th>
+ * <th>Encoders</th>
+ * </tr>
+ * </thead>
+ * <tbody>
+ * <tr>
+ * <td>{@link android.os.Build.VERSION_CODES#LOLLIPOP}</td>
+ * <td rowspan=3>{@link MediaFormat#KEY_MIME}<sup>*</sup>,<br>
+ * {@link MediaFormat#KEY_SAMPLE_RATE},<br>
+ * {@link MediaFormat#KEY_CHANNEL_COUNT},</td>
+ * <td>{@link MediaFormat#KEY_MIME}<sup>*</sup>,<br>
+ * {@link CodecCapabilities#FEATURE_AdaptivePlayback}<sup>D</sup>,<br>
+ * {@link CodecCapabilities#FEATURE_SecurePlayback}<sup>D</sup>,<br>
+ * {@link CodecCapabilities#FEATURE_TunneledPlayback}<sup>D</sup>,<br>
+ * {@link MediaFormat#KEY_WIDTH},<br>
+ * {@link MediaFormat#KEY_HEIGHT},<br>
+ * <strong>no</strong> {@code KEY_FRAME_RATE}</td>
+ * <td rowspan=10>as to the left, plus<br>
+ * {@link MediaFormat#KEY_BITRATE_MODE},<br>
+ * {@link MediaFormat#KEY_PROFILE}
+ * (and/or {@link MediaFormat#KEY_AAC_PROFILE}<sup>~</sup>),<br>
+ * <!-- {link MediaFormat#KEY_QUALITY},<br> -->
+ * {@link MediaFormat#KEY_COMPLEXITY}
+ * (and/or {@link MediaFormat#KEY_FLAC_COMPRESSION_LEVEL}<sup>~</sup>)</td>
+ * </tr><tr>
+ * <td>{@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1}</td>
+ * <td rowspan=2>as above, plus<br>
+ * {@link MediaFormat#KEY_FRAME_RATE}</td>
+ * </tr><tr>
+ * <td>{@link android.os.Build.VERSION_CODES#M}</td>
+ * </tr><tr>
+ * <td>{@link android.os.Build.VERSION_CODES#N}</td>
+ * <td rowspan=2>as above, plus<br>
+ * {@link MediaFormat#KEY_PROFILE},<br>
+ * <!-- {link MediaFormat#KEY_MAX_BIT_RATE},<br> -->
+ * {@link MediaFormat#KEY_BIT_RATE}</td>
+ * <td rowspan=2>as above, plus<br>
+ * {@link MediaFormat#KEY_PROFILE},<br>
+ * {@link MediaFormat#KEY_LEVEL}<sup>+</sup>,<br>
+ * <!-- {link MediaFormat#KEY_MAX_BIT_RATE},<br> -->
+ * {@link MediaFormat#KEY_BIT_RATE},<br>
+ * {@link CodecCapabilities#FEATURE_IntraRefresh}<sup>E</sup></td>
+ * </tr><tr>
+ * <td>{@link android.os.Build.VERSION_CODES#N_MR1}</td>
+ * </tr><tr>
+ * <td>{@link android.os.Build.VERSION_CODES#O}</td>
+ * <td rowspan=3 colspan=2>as above, plus<br>
+ * {@link CodecCapabilities#FEATURE_PartialFrame}<sup>D</sup></td>
+ * </tr><tr>
+ * <td>{@link android.os.Build.VERSION_CODES#O_MR1}</td>
+ * </tr><tr>
+ * <td>{@link android.os.Build.VERSION_CODES#P}</td>
+ * </tr><tr>
+ * <td>{@link android.os.Build.VERSION_CODES#Q}</td>
+ * <td colspan=2>as above, plus<br>
+ * {@link CodecCapabilities#FEATURE_FrameParsing}<sup>D</sup>,<br>
+ * {@link CodecCapabilities#FEATURE_MultipleFrames},<br>
+ * {@link CodecCapabilities#FEATURE_DynamicTimestamp}</td>
+ * </tr><tr>
+ * <td>{@link android.os.Build.VERSION_CODES#R}</td>
+ * <td colspan=2>as above, plus<br>
+ * {@link CodecCapabilities#FEATURE_LowLatency}<sup>D</sup></td>
+ * </tr>
+ * <tr>
+ * <td colspan=4>
+ * <p class=note><strong>Notes:</strong><br>
+ * *: must be specified; otherwise, method returns {@code false}.<br>
+ * +: method does not verify that the format parameters are supported
+ * by the specified level.<br>
+ * D: decoders only<br>
+ * E: encoders only<br>
+ * ~: if both keys are provided values must match
+ * </td>
+ * </tr>
+ * </tbody>
+ * </table>
+ *
+ * @param format media format with optional feature directives.
+ * @return whether the codec capabilities support the given format
+ * and feature requests.
+ */
+ bool isFormatSupported(const sp<AMessage> &format) const;
+
+ /**
+ * If the CodecCapabilities contains an AudioCapabilities.
+ *
+ * Not a public API to users.
+ */
+ bool isAudio() const;
+
+ /**
+ * If the CodecCapabilities contains a VideoCapabilities.
+ *
+ * Not a public API to users.
+ */
+ bool isVideo() const;
+
+ /**
+ * If the CodecCapabilities contains an EncoderCapabilities.
+ *
+ * Not a public API to users.
+ */
+ bool isEncoder() const;
+
private:
std::string mMediaType;
std::vector<ProfileLevel> mProfileLevels;
+ std::vector<uint32_t> mColorFormats;
+ int32_t mMaxSupportedInstances;
+
+ sp<AMessage> mDefaultFormat;
+ sp<AMessage> mCapabilitiesInfo;
+
+ // Features
+ std::set<std::string> mFeaturesSupported;
+ std::set<std::string> mFeaturesRequired;
std::shared_ptr<AudioCapabilities> mAudioCaps;
std::shared_ptr<VideoCapabilities> mVideoCaps;
+ std::shared_ptr<EncoderCapabilities> mEncoderCaps;
+
+ bool supportsProfileLevel(int32_t profile, int32_t level) const;
+ std::vector<Feature> getValidFeatures() const;
+ int32_t getErrors() const;
};
} // namespace android
diff --git a/media/libmedia/include/media/CodecCapabilitiesUtils.h b/media/libmedia/include/media/CodecCapabilitiesUtils.h
index 7ca536a..eb62bf9 100644
--- a/media/libmedia/include/media/CodecCapabilitiesUtils.h
+++ b/media/libmedia/include/media/CodecCapabilitiesUtils.h
@@ -42,6 +42,21 @@
}
};
+struct Feature {
+ std::string mName;
+ int mValue;
+ bool mDefault;
+ bool mInternal;
+ Feature(std::string name, int value, bool def, bool internal) {
+ mName = name;
+ mValue = value;
+ mDefault = def;
+ mInternal = internal;
+ }
+ Feature(std::string name, int value, bool def) :
+ Feature(name, value, def, false /* internal */) {}
+};
+
/**
* Immutable class for describing the range of two numeric values.
*
diff --git a/media/libmedia/include/media/EncoderCapabilities.h b/media/libmedia/include/media/EncoderCapabilities.h
new file mode 100644
index 0000000..a9654bb
--- /dev/null
+++ b/media/libmedia/include/media/EncoderCapabilities.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2024, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ENCODER_CAPABILITIES_H_
+
+#define ENCODER_CAPABILITIES_H_
+
+#include <media/CodecCapabilitiesUtils.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+/**
+ * A class that supports querying the encoding capabilities of a codec.
+ */
+struct EncoderCapabilities {
+ /**
+ * Returns the supported range of quality values.
+ *
+ * Quality is implementation-specific. As a general rule, a higher quality
+ * setting results in a better image quality and a lower compression ratio.
+ */
+ const Range<int>& getQualityRange();
+
+ /**
+ * Returns the supported range of encoder complexity values.
+ * <p>
+ * Some codecs may support multiple complexity levels, where higher
+ * complexity values use more encoder tools (e.g. perform more
+ * intensive calculations) to improve the quality or the compression
+ * ratio. Use a lower value to save power and/or time.
+ */
+ const Range<int>& getComplexityRange();
+
+ /** Constant quality mode */
+ inline static constexpr int BITRATE_MODE_CQ = 0;
+ /** Variable bitrate mode */
+ inline static constexpr int BITRATE_MODE_VBR = 1;
+ /** Constant bitrate mode */
+ inline static constexpr int BITRATE_MODE_CBR = 2;
+ /** Constant bitrate mode with frame drops */
+ inline static constexpr int BITRATE_MODE_CBR_FD = 3;
+
+ /**
+ * Query whether a bitrate mode is supported.
+ */
+ bool isBitrateModeSupported(int mode);
+
+ /** @hide */
+ static std::shared_ptr<EncoderCapabilities> Create(std::string mediaType,
+ std::vector<ProfileLevel> profLevs, const sp<AMessage> &format);
+
+ /** @hide */
+ void getDefaultFormat(sp<AMessage> &format);
+
+ /** @hide */
+ bool supportsFormat(const sp<AMessage> &format);
+
+private:
+ inline static const Feature sBitrateModes[] = {
+ Feature("VBR", BITRATE_MODE_VBR, true),
+ Feature("CBR", BITRATE_MODE_CBR, false),
+ Feature("CQ", BITRATE_MODE_CQ, false),
+ Feature("CBR-FD", BITRATE_MODE_CBR_FD, false)
+ };
+ static int ParseBitrateMode(std::string mode);
+
+ std::string mMediaType;
+ std::vector<ProfileLevel> mProfileLevels;
+
+ Range<int> mQualityRange;
+ Range<int> mComplexityRange;
+ int mBitControl;
+ int mDefaultComplexity;
+ int mDefaultQuality;
+ std::string mQualityScale;
+
+ /* no public constructor */
+ EncoderCapabilities() {}
+ void init(std::string mediaType, std::vector<ProfileLevel> profLevs,
+ const sp<AMessage> &format);
+ void applyLevelLimits();
+ void parseFromInfo(const sp<AMessage> &format);
+ bool supports(std::optional<int> complexity, std::optional<int> quality,
+ std::optional<int> profile);
+};
+
+} // namespace android
+
+#endif // ENCODER_CAPABILITIES_H_
\ No newline at end of file
diff --git a/media/libmedia/include/media/MediaCodecInfo.h b/media/libmedia/include/media/MediaCodecInfo.h
index 72aca98..60e383a 100644
--- a/media/libmedia/include/media/MediaCodecInfo.h
+++ b/media/libmedia/include/media/MediaCodecInfo.h
@@ -192,6 +192,7 @@
Attributes getAttributes() const;
void getSupportedMediaTypes(Vector<AString> *mediaTypes) const;
const sp<Capabilities> getCapabilitiesFor(const char *mediaType) const;
+ const std::shared_ptr<CodecCapabilities> getCodecCapsFor(const char *mediaType) const;
const char *getCodecName() const;
/**
@@ -229,14 +230,21 @@
status_t writeToParcel(Parcel *parcel) const;
private:
+ /**
+ * Max supported instances setting from MediaCodecList global setting.
+ */
+ static int32_t sMaxSupportedInstances;
+
AString mName;
AString mOwner;
Attributes mAttributes;
KeyedVector<AString, sp<Capabilities> > mCaps;
+ KeyedVector<AString, std::shared_ptr<CodecCapabilities>> mCodecCaps;
Vector<AString> mAliases;
uint32_t mRank;
ssize_t getCapabilityIndex(const char *mediaType) const;
+ ssize_t getCodecCapIndex(const char *mediaType) const;
/**
* Construct an `MediaCodecInfo` object. After the construction, its
@@ -264,6 +272,15 @@
*/
struct MediaCodecInfoWriter {
/**
+ * Get CodecCapabilities from Capabilities.
+ */
+ static std::shared_ptr<CodecCapabilities> BuildCodecCapabilities(const char *mediaType,
+ sp<MediaCodecInfo::Capabilities> caps, bool isEncoder, int maxSupportedInstances = 0);
+ /**
+ * Set the max supported instances global setting from MediaCodecList.
+ */
+ static void SetMaxSupportedInstances(int32_t maxSupportedInstances);
+ /**
* Set the name of the codec.
*
* @param name The new name.
@@ -319,6 +336,10 @@
* @param rank The rank of the component.
*/
void setRank(uint32_t rank);
+ /**
+ * Create CodecCapabilities map from Capabilities.
+ */
+ void createCodecCaps();
private:
/**
* The associated `MediaCodecInfo`.
diff --git a/media/libmedia/tests/codeccapabilities/CodecCapabilitiesTest.cpp b/media/libmedia/tests/codeccapabilities/CodecCapabilitiesTest.cpp
index c1bd65a..e59d4d6 100644
--- a/media/libmedia/tests/codeccapabilities/CodecCapabilitiesTest.cpp
+++ b/media/libmedia/tests/codeccapabilities/CodecCapabilitiesTest.cpp
@@ -227,3 +227,147 @@
EXPECT_EQ(achievableFR1080p.value().lower(), 569);
EXPECT_EQ(achievableFR1080p.value().upper(), 572);
}
+
+class EncoderCapsAacTest : public testing::Test {
+protected:
+ EncoderCapsAacTest() {
+ std::string mediaType = MIMETYPE_AUDIO_AAC;
+
+ sp<AMessage> details = new AMessage;
+ details->setString("bitrate-range", "8000-960000");
+ details->setString("max-channel-count", "6");
+ details->setString("sample-rate-ranges",
+ "8000,11025,12000,16000,22050,24000,32000,44100,48000");
+
+ std::vector<ProfileLevel> profileLevel{
+ ProfileLevel(2, 0),
+ ProfileLevel(5, 0),
+ ProfileLevel(29, 0),
+ ProfileLevel(23, 0),
+ ProfileLevel(39, 0),
+ };
+
+ encoderCaps = EncoderCapabilities::Create(mediaType, profileLevel, details);
+ }
+
+ std::shared_ptr<EncoderCapabilities> encoderCaps;
+};
+
+
+TEST_F(EncoderCapsAacTest, EncoderCaps_AAC_ComplexityRange) {
+ const Range<int>& complexityRange = encoderCaps->getComplexityRange();
+ EXPECT_EQ(complexityRange.lower(), 0);
+ EXPECT_EQ(complexityRange.upper(), 0);
+}
+
+TEST_F(EncoderCapsAacTest, EncoderCaps_AAC_QualityRange) {
+ const Range<int>& qualityRange = encoderCaps->getQualityRange();
+ EXPECT_EQ(qualityRange.lower(), 0);
+ EXPECT_EQ(qualityRange.upper(), 0);
+}
+
+TEST_F(EncoderCapsAacTest, EncoderCaps_AAC_SupportedBitrateMode) {
+ EXPECT_FALSE(encoderCaps->isBitrateModeSupported(BITRATE_MODE_CBR));
+ EXPECT_TRUE(encoderCaps->isBitrateModeSupported(BITRATE_MODE_VBR));
+ EXPECT_FALSE(encoderCaps->isBitrateModeSupported(BITRATE_MODE_CQ));
+ EXPECT_FALSE(encoderCaps->isBitrateModeSupported(BITRATE_MODE_CBR_FD));
+}
+
+class EncoderCapsFlacTest : public testing::Test {
+protected:
+ EncoderCapsFlacTest() {
+ std::string mediaType = MIMETYPE_AUDIO_FLAC;
+
+ sp<AMessage> details = new AMessage;
+ details->setString("bitrate-range", "1-21000000");
+ details->setString("complexity-default", "5");
+ details->setString("complexity-range", "0-8");
+ details->setString("feature-bitrate-modes", "CQ");
+ details->setString("max-channel-count", "2");
+ details->setString("sample-rate-ranges", "1-655350");
+
+ std::vector<ProfileLevel> profileLevel;
+
+ encoderCaps = EncoderCapabilities::Create(mediaType, profileLevel, details);
+ }
+
+ std::shared_ptr<EncoderCapabilities> encoderCaps;
+};
+
+TEST_F(EncoderCapsFlacTest, EncoderCaps_FLAC_ComplexityRange) {
+ const Range<int>& complexityRange = encoderCaps->getComplexityRange();
+ EXPECT_EQ(complexityRange.lower(), 0);
+ EXPECT_EQ(complexityRange.upper(), 8);
+}
+
+TEST_F(EncoderCapsFlacTest, EncoderCaps_FLAC_QualityRange) {
+ const Range<int>& qualityRange = encoderCaps->getQualityRange();
+ EXPECT_EQ(qualityRange.lower(), 0);
+ EXPECT_EQ(qualityRange.upper(), 0);
+}
+
+TEST_F(EncoderCapsFlacTest, EncoderCaps_FLAC_SupportedBitrateMode) {
+ EXPECT_FALSE(encoderCaps->isBitrateModeSupported(BITRATE_MODE_CBR));
+ EXPECT_FALSE(encoderCaps->isBitrateModeSupported(BITRATE_MODE_VBR));
+ EXPECT_TRUE(encoderCaps->isBitrateModeSupported(BITRATE_MODE_CQ));
+ EXPECT_FALSE(encoderCaps->isBitrateModeSupported(BITRATE_MODE_CBR_FD));
+}
+
+class EncoderCapsHevcTest : public testing::Test {
+protected:
+ EncoderCapsHevcTest() {
+ std::string mediaType = MIMETYPE_VIDEO_HEVC;
+
+ sp<AMessage> details = new AMessage;
+ details->setString("alignment", "2x2");
+ details->setString("bitrate-range", "1-120000000");
+ details->setString("block-count-range", "1-8160");
+ details->setString("block-size", "32x32");
+ details->setString("blocks-per-second-range", "1-979200");
+ details->setString("feature-bitrate-modes", "VBR,CBR,CQ,CBR-FD");
+ details->setInt32("feature-can-swap-width-height", 1);
+ details->setInt32("feature-qp-bounds", 0);
+ details->setInt32("feature-vq-minimum-quality", 0);
+ details->setString("max-concurrent-instances", "16");
+ details->setString("measured-frame-rate-1280x720-range", "154-198");
+ details->setString("measured-frame-rate-1920x1080-range", "46-97");
+ details->setString("measured-frame-rate-320x240-range", "371-553");
+ details->setString("measured-frame-rate-720x480-range", "214-305");
+ details->setString("performance-point-1280x720-range", "240");
+ details->setString("performance-point-3840x2160-range", "120");
+ details->setString("quality-default", "57");
+ details->setString("quality-range", "0-100");
+ details->setString("quality-scale", "linear");
+ details->setString("size-range", "64x64-3840x2176");
+
+ std::vector<ProfileLevel> profileLevel{
+ ProfileLevel(1, 2097152),
+ ProfileLevel(2, 2097152),
+ ProfileLevel(4096, 2097152),
+ ProfileLevel(8192, 2097152),
+ };
+
+ encoderCaps = EncoderCapabilities::Create(mediaType, profileLevel, details);
+ }
+
+ std::shared_ptr<EncoderCapabilities> encoderCaps;
+};
+
+TEST_F(EncoderCapsHevcTest, EncoderCaps_HEVC_ComplexityRange) {
+ const Range<int>& complexityRange = encoderCaps->getComplexityRange();
+ EXPECT_EQ(complexityRange.lower(), 0);
+ EXPECT_EQ(complexityRange.upper(), 0);
+}
+
+TEST_F(EncoderCapsHevcTest, EncoderCaps_HEVC_QualityRange) {
+ const Range<int>& qualityRange = encoderCaps->getQualityRange();
+ EXPECT_EQ(qualityRange.lower(), 0);
+ EXPECT_EQ(qualityRange.upper(), 100);
+}
+
+TEST_F(EncoderCapsHevcTest, EncoderCaps_HEVC_SupportedBitrateMode) {
+ EXPECT_TRUE(encoderCaps->isBitrateModeSupported(BITRATE_MODE_CBR));
+ EXPECT_TRUE(encoderCaps->isBitrateModeSupported(BITRATE_MODE_VBR));
+ EXPECT_TRUE(encoderCaps->isBitrateModeSupported(BITRATE_MODE_CQ));
+ EXPECT_TRUE(encoderCaps->isBitrateModeSupported(BITRATE_MODE_CBR_FD));
+}
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index b466f18..92ac451 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -99,6 +99,7 @@
static_libs: [
"libstagefright_esds",
+ "android.media.extractor.flags-aconfig-cc",
],
export_include_dirs: [
@@ -325,6 +326,7 @@
static_libs: [
"android.media.codec-aconfig-cc",
+ "android.media.extractor.flags-aconfig-cc",
"com.android.media.flags.editing-aconfig-cc",
"framework-permission-aidl-cpp",
"libmedia_ndkformatpriv",
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index eb7edaf..f917aa2 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -6092,9 +6092,9 @@
}
if (csd->size() == 0) {
ALOGW("csd-%zu size is 0", i);
+ } else {
+ mCSD.push_back(csd);
}
-
- mCSD.push_back(csd);
++i;
}
diff --git a/media/libstagefright/OmxInfoBuilder.cpp b/media/libstagefright/OmxInfoBuilder.cpp
index 79ffdeb..1cb8f14 100644
--- a/media/libstagefright/OmxInfoBuilder.cpp
+++ b/media/libstagefright/OmxInfoBuilder.cpp
@@ -21,6 +21,8 @@
#define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
#endif
+#include <cstdlib>
+
#include <android-base/properties.h>
#include <utils/Log.h>
@@ -131,6 +133,10 @@
for (const auto& p : serviceAttributes) {
writer->addGlobalSetting(
p.key.c_str(), p.value.c_str());
+ if (p.key == "max-concurrent-instances") {
+ MediaCodecInfoWriter::SetMaxSupportedInstances(
+ (int32_t)strtol(p.value.c_str(), NULL, 10));
+ }
}
// Convert roles to lists of codecs
@@ -217,6 +223,8 @@
ALOGW("Fail to add media type %s to codec %s",
typeName.c_str(), nodeName.c_str());
info->removeMediaType(typeName.c_str());
+ } else {
+ info->createCodecCaps();
}
}
}
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 86741a6..50eeb62 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -44,6 +44,8 @@
#include <media/AudioParameter.h>
#include <system/audio.h>
+#include <com_android_media_extractor_flags.h>
+
// TODO : Remove the defines once mainline media is built against NDK >= 31.
// The mp4 extractor is part of mainline and builds against NDK 29 as of
// writing. These keys are available only from NDK 31:
@@ -1443,6 +1445,17 @@
buffer->meta()->setInt64("timeUs", 0);
msg->setBuffer("csd-0", buffer);
parseAV1ProfileLevelFromCsd(buffer, msg);
+ } else if (com::android::media::extractor::flags::extractor_mp4_enable_apv() &&
+ meta->findData(kKeyAPVC, &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(kKeyESDS, &type, &data, &size)) {
ESDS esds((const char *)data, size);
if (esds.InitCheck() != (status_t)OK) {
@@ -2091,6 +2104,9 @@
} else if (mime == MEDIA_MIMETYPE_VIDEO_AV1 ||
mime == MEDIA_MIMETYPE_IMAGE_AVIF) {
meta->setData(kKeyAV1C, 0, csd0->data(), csd0->size());
+ } else if (com::android::media::extractor::flags::extractor_mp4_enable_apv() &&
+ mime == MEDIA_MIMETYPE_VIDEO_APV) {
+ meta->setData(kKeyAPVC, 0, csd0->data(), csd0->size());
} else if (mime == MEDIA_MIMETYPE_VIDEO_DOLBY_VISION) {
int32_t profile = -1;
uint8_t blCompatibilityId = -1;
diff --git a/media/libstagefright/data/media_codecs_google_c2_video.xml b/media/libstagefright/data/media_codecs_google_c2_video.xml
index 72a2551..2fb2d59 100644
--- a/media/libstagefright/data/media_codecs_google_c2_video.xml
+++ b/media/libstagefright/data/media_codecs_google_c2_video.xml
@@ -101,6 +101,7 @@
<Limit name="bitrate" range="1-240000000"/>
<Limit name="block-size" value="16x16" />
<Limit name="block-count" range="1-32768" /> <!-- max 4096x2048 equivalent -->
+ <Feature name="dynamic-color-aspects" />
<Attribute name="software-codec"/>
</MediaCodec>
</Decoders>
diff --git a/media/libstagefright/data/media_codecs_sw.xml b/media/libstagefright/data/media_codecs_sw.xml
index 20c97dc..c79ac5c 100644
--- a/media/libstagefright/data/media_codecs_sw.xml
+++ b/media/libstagefright/data/media_codecs_sw.xml
@@ -262,6 +262,7 @@
<Limit name="block-size" value="16x16" />
<Limit name="block-count" range="1-32768" /> <!-- max 4096x2048 equivalent -->
<Feature name="adaptive-playback" />
+ <Feature name="dynamic-color-aspects" />
<Attribute name="software-codec"/>
</MediaCodec>
</Decoders>
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
index 8f2f162..b0f671d 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
@@ -854,12 +854,17 @@
}
inline constexpr char FEATURE_AdaptivePlayback[] = "adaptive-playback";
+inline constexpr char FEATURE_DynamicTimestamp[] = "dynamic-timestamp";
inline constexpr char FEATURE_EncodingStatistics[] = "encoding-statistics";
+inline constexpr char FEATURE_FrameParsing[] = "frame-parsing";
+inline constexpr char FEATURE_HdrEditing[] = "hdr-editing";
inline constexpr char FEATURE_IntraRefresh[] = "intra-refresh";
+inline constexpr char FEATURE_LowLatency[] = "low-latency";
inline constexpr char FEATURE_MultipleFrames[] = "multiple-frames";
inline constexpr char FEATURE_PartialFrame[] = "partial-frame";
inline constexpr char FEATURE_QpBounds[] = "qp-bounds";
inline constexpr char FEATURE_SecurePlayback[] = "secure-playback";
+inline constexpr char FEATURE_SpecialCodec[] = "special-codec";
inline constexpr char FEATURE_TunneledPlayback[] = "tunneled-playback";
// from MediaFormat.java
diff --git a/media/module/libapexcodecs/Android.bp b/media/module/libapexcodecs/Android.bp
index 790b749..dbda81b 100644
--- a/media/module/libapexcodecs/Android.bp
+++ b/media/module/libapexcodecs/Android.bp
@@ -40,6 +40,15 @@
}
+cc_library_headers {
+ name: "libapexcodecs-header",
+ visibility: [
+ "//frameworks/av/apex:__subpackages__",
+ "//frameworks/av/media/codec2/hal/client",
+ ],
+ export_include_dirs: ["include"],
+}
+
cc_library {
name: "libapexcodecs-testing",
defaults: ["libapexcodecs-defaults"],
diff --git a/media/module/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp b/media/module/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
index d21908f..7905e4f 100644
--- a/media/module/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
+++ b/media/module/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
@@ -458,6 +458,12 @@
if (bufferInfo.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
LOG(DEBUG) << "EOS from decoder.";
+ // NOTE - b/360057459
+ // There is a synchronization problem between feeding the frame to the encoder input surface
+ // and signaling end of stream.
+ // Waiting before signaling end of stream so that input surface has time to feed remaining
+ // frames to the encoder.
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
media_status_t status = AMediaCodec_signalEndOfInputStream(mEncoder->getCodec());
if (status != AMEDIA_OK) {
LOG(ERROR) << "SignalEOS on encoder returned error: " << status;
diff --git a/media/ndk/NdkImageReader.cpp b/media/ndk/NdkImageReader.cpp
index 995c674..889ddad 100644
--- a/media/ndk/NdkImageReader.cpp
+++ b/media/ndk/NdkImageReader.cpp
@@ -678,6 +678,28 @@
}
}
+media_status_t
+AImageReader::setUsage(uint64_t usage) {
+ Mutex::Autolock _l(mLock);
+ if (!mIsOpen || mBufferItemConsumer == nullptr) {
+ ALOGE("not ready to perform setUsage()");
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ if (mUsage == usage) {
+ return AMEDIA_OK;
+ }
+
+ uint64_t halUsage = AHardwareBuffer_convertToGrallocUsageBits(mUsage);
+ status_t ret = mBufferItemConsumer->setConsumerUsageBits(halUsage);
+ if (ret != OK) {
+ ALOGE("setConsumerUsageBits() failed %d", ret);
+ return AMEDIA_ERROR_UNKNOWN;
+ }
+ mUsage = usage;
+ mHalUsage = halUsage;
+ return AMEDIA_OK;
+}
+
static
media_status_t validateParameters(int32_t width, int32_t height, int32_t format,
uint64_t usage, int32_t maxImages,
@@ -935,3 +957,14 @@
reader->setBufferRemovedListener(listener);
return AMEDIA_OK;
}
+
+EXPORT
+media_status_t AImageReader_setUsage(
+ AImageReader *reader, uint64_t usage) {
+ ALOGV("%s", __FUNCTION__);
+ if (reader == nullptr) {
+ ALOGE("%s: invalid argument! reader %p", __FUNCTION__, reader);
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ return reader->setUsage(usage);
+}
diff --git a/media/ndk/NdkImageReaderPriv.h b/media/ndk/NdkImageReaderPriv.h
index 985f42b..89a33f8 100644
--- a/media/ndk/NdkImageReaderPriv.h
+++ b/media/ndk/NdkImageReaderPriv.h
@@ -20,6 +20,7 @@
#include <inttypes.h>
#include <media/NdkImageReader.h>
+#include <media-vndk/VndkImageReader.h>
#include <utils/List.h>
#include <utils/Mutex.h>
@@ -68,6 +69,7 @@
media_status_t setImageListener(AImageReader_ImageListener* listener);
media_status_t setBufferRemovedListener(AImageReader_BufferRemovedListener* listener);
+ media_status_t setUsage(uint64_t usage);
media_status_t acquireNextImage(/*out*/AImage** image, /*out*/int* fenceFd);
media_status_t acquireLatestImage(/*out*/AImage** image, /*out*/int* fenceFd);
@@ -121,7 +123,7 @@
const int32_t mWidth;
const int32_t mHeight;
int32_t mFormat;
- const uint64_t mUsage; // AHARDWAREBUFFER_USAGE_* flags.
+ uint64_t mUsage; // AHARDWAREBUFFER_USAGE_* flags.
const int32_t mMaxImages;
// TODO(jwcai) Seems completely unused in AImageReader class.
diff --git a/media/ndk/include/media-vndk/VndkImageReader.h b/media/ndk/include/media-vndk/VndkImageReader.h
new file mode 100644
index 0000000..c67a38c
--- /dev/null
+++ b/media/ndk/include/media-vndk/VndkImageReader.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _VNDK_IMAGE_READER_H
+#define _VNDK_IMAGE_READER_H
+
+// vndk is a superset of the NDK
+#include <media/NdkImageReader.h>
+
+__BEGIN_DECLS
+
+/**
+ * Set the usage of this image reader.
+ *
+ * <p>Note that calling this method will replace the previously set usage.</p>
+ *
+ * <p>Note: This will trigger re-allocation, could cause producer failures mid-stream
+ * if the new usage combination isn't supported, and thus should be avoided as much as
+ * possible regardless.</p>
+ *
+ * Available since API level 36.
+ *
+ * @param reader The image reader of interest.
+ * @param usage specifies how the consumer will access the AImage.
+ * See {@link AImageReader_newWithUsage} parameter description for more details.
+ * @return <ul>
+ * <li>{@link AMEDIA_OK} if the method call succeeds.</li>
+ * <li>{@link AMEDIA_ERROR_INVALID_PARAMETER} if reader is NULL.</li>
+ * <li>{@link AMEDIA_ERROR_UNKNOWN} if the method fails for some other reasons.</li></ul>
+ *
+ * @see AImage_getHardwareBuffer
+ */
+media_status_t AImageReader_setUsage(
+ AImageReader* _Nonnull reader, uint64_t usage) __INTRODUCED_IN(36);
+
+__END_DECLS
+
+#endif //_VNDK_IMAGE_READER_H
diff --git a/media/ndk/libmediandk.map.txt b/media/ndk/libmediandk.map.txt
index 262c169..8fb203f 100644
--- a/media/ndk/libmediandk.map.txt
+++ b/media/ndk/libmediandk.map.txt
@@ -16,6 +16,7 @@
AImageReader_newWithDataSpace; # introduced=UpsideDownCake
AImageReader_setBufferRemovedListener; # introduced=26
AImageReader_setImageListener; # introduced=24
+ AImageReader_setUsage; # introduced=36 llndk
AImage_delete; # introduced=24
AImage_deleteAsync; # introduced=26
AImage_getCropRect; # introduced=24
diff --git a/media/utils/EventLogTags.logtags b/media/utils/EventLogTags.logtags
index c397f34..5b98b0f 100644
--- a/media/utils/EventLogTags.logtags
+++ b/media/utils/EventLogTags.logtags
@@ -31,7 +31,7 @@
# 6: Percent
# Default value for data of type int/long is 2 (bytes).
#
-# See system/core/logcat/event.logtags for the original definition of the tags.
+# See system/logging/logcat/event.logtags for the original definition of the tags.
# 61000 - 61199 reserved for audioserver
diff --git a/media/utils/include/mediautils/BinderGenericUtils.h b/media/utils/include/mediautils/BinderGenericUtils.h
index c2bbde1..5f3b9f3 100644
--- a/media/utils/include/mediautils/BinderGenericUtils.h
+++ b/media/utils/include/mediautils/BinderGenericUtils.h
@@ -298,20 +298,21 @@
class RequestDeathNotificationNdk {
public:
RequestDeathNotificationNdk(
- const ::ndk::SpAIBinder &binder, std::function<void()> &&onBinderDied)
- : mOnBinderDied(std::move(onBinderDied)),
- mRecipient(::AIBinder_DeathRecipient_new(OnBinderDiedStatic),
- &AIBinder_DeathRecipient_delete), mStatus{AIBinder_linkToDeath(
- binder.get(), mRecipient.get(), /* cookie */ this)} {
+ const ::ndk::SpAIBinder &binder, std::function<void()>&& onBinderDied)
+ : mRecipient(::AIBinder_DeathRecipient_new(OnBinderDiedStatic),
+ &AIBinder_DeathRecipient_delete),
+ mStatus{(AIBinder_DeathRecipient_setOnUnlinked( // sets cookie deleter
+ mRecipient.get(), OnBinderDiedUnlinkedStatic),
+ AIBinder_linkToDeath( // registers callback
+ binder.get(), mRecipient.get(),
+ // we create functional cookie ptr which may outlive this object.
+ new std::function<void()>(std::move(onBinderDied))))} {
ALOGW_IF(mStatus != OK, "%s: AIBinder_linkToDeath status:%d", __func__, mStatus);
- // We do not use AIBinder_DeathRecipient_setOnUnlinked() to do resource deallocation
- // as the functor mOnBinderDied is kept alive by this class.
}
~RequestDeathNotificationNdk() {
- // The AIBinder_DeathRecipient dtor automatically unlinks all registered notifications,
- // so AIBinder_unlinkToDeath() is not needed here (elsewise we need to maintain a
- // AIBinder_Weak here).
+ // mRecipient's unique_ptr calls AIBinder_DeathRecipient_delete to unlink the recipient.
+ // Then OnBinderDiedUnlinkedStatic eventually deletes the cookie.
}
status_t getStatus() const {
@@ -319,15 +320,14 @@
}
private:
- void onBinderDied() {
- mOnBinderDied();
+ static void OnBinderDiedUnlinkedStatic(void* cookie) {
+ delete reinterpret_cast<std::function<void()>*>(cookie);
}
- static void OnBinderDiedStatic(void *cookie) {
- reinterpret_cast<RequestDeathNotificationNdk *>(cookie)->onBinderDied();
+ static void OnBinderDiedStatic(void* cookie) {
+ (*reinterpret_cast<std::function<void()>*>(cookie))();
}
- const std::function<void()> mOnBinderDied;
const std::unique_ptr<AIBinder_DeathRecipient, decltype(
&AIBinder_DeathRecipient_delete)>
mRecipient;
@@ -362,8 +362,11 @@
/**
* Requests a death notification.
*
- * An opaque handle is returned - after clearing it is guaranteed that
- * no notification will occur.
+ * An opaque handle is returned. If the service is already dead, the
+ * handle will be null.
+ *
+ * Implementation detail: A callback may occur after the handle is released
+ * if a death notification is in progress.
*
* The callback will be of form void onBinderDied();
*/
diff --git a/media/utils/include/mediautils/ServiceSingleton.h b/media/utils/include/mediautils/ServiceSingleton.h
index 644d9cd..fe8e9f2 100644
--- a/media/utils/include/mediautils/ServiceSingleton.h
+++ b/media/utils/include/mediautils/ServiceSingleton.h
@@ -175,10 +175,14 @@
if (service_new) {
mValid = true;
service = std::move(service_new);
- setDeathNotifier_l<Service>();
- auto service_fixed = service; // we're releasing the mutex.
+ // service is a reference, so we copy to service_fixed as
+ // we're releasing the mutex.
+ const auto service_fixed = service;
ul.unlock();
traits->onNewService(interfaceFromBase<Service>(service_fixed));
+ ul.lock();
+ setDeathNotifier_l<Service>(service_fixed);
+ ul.unlock();
mCv.notify_all();
return service_fixed;
}
@@ -297,8 +301,10 @@
if (originalService != service) {
mService = service;
mValid = true;
- setDeathNotifier_l<Service>();
+ ul.unlock();
traits->onNewService(service);
+ ul.lock();
+ setDeathNotifier_l<Service>(service);
}
ul.unlock();
mCv.notify_all();
@@ -310,8 +316,12 @@
// sets the death notifier for mService (mService must be non-null).
template <typename Service>
- void setDeathNotifier_l() REQUIRES(mMutex) {
- auto base = std::get<BaseInterfaceType<Service>>(mService);
+ void setDeathNotifier_l(const BaseInterfaceType<Service>& base) REQUIRES(mMutex) {
+ if (base != std::get<BaseInterfaceType<Service>>(mService)) {
+ ALOGW("%s: service has changed for %s, skipping death notification registration",
+ __func__, toString(Service::descriptor).c_str());
+ return;
+ }
auto service = interfaceFromBase<Service>(base);
const auto binder = binderFromInterface(service);
if (binder.get()) {
@@ -326,6 +336,8 @@
}
traits->onServiceDied(service);
});
+ // Implementation detail: if the service has already died,
+ // we do not call the death notification, but log the issue here.
ALOGW_IF(!mDeathNotificationHandle, "%s: cannot register death notification %s"
" (already died?)",
__func__, toString(Service::descriptor).c_str());
diff --git a/media/utils/tests/service_singleton_tests.cpp b/media/utils/tests/service_singleton_tests.cpp
index 8656a20..18d7f3d 100644
--- a/media/utils/tests/service_singleton_tests.cpp
+++ b/media/utils/tests/service_singleton_tests.cpp
@@ -258,7 +258,9 @@
// we can also request our own death notifications (outside of the service traits).
handle3 = mediautils::requestDeathNotification(service, [&] { ++listenerServiceDied; });
+ EXPECT_TRUE(handle3);
handle4 = mediautils::requestDeathNotification(service2, [&] { ++listenerServiceDied; });
+ EXPECT_TRUE(handle4);
}
EXPECT_EQ(4, sNewService);
@@ -352,6 +354,13 @@
EXPECT_EQ(6, listenerServiceCreated); // listener associated with service name picks up info.
+ // get service pointers that will be made stale later.
+ auto stale_service = mediautils::getService<IServiceSingletonTest>();
+ EXPECT_TRUE(stale_service); // not stale yet.
+
+ auto stale_service2 = mediautils::getService<aidl::IServiceSingletonTest>();
+ EXPECT_TRUE(stale_service2); // not stale yet.
+
// Release the service.
remoteWorker->putc('b');
EXPECT_EQ('b', remoteWorker->getc());
@@ -362,4 +371,15 @@
EXPECT_EQ(4, sServiceDied);
EXPECT_EQ(2, sNewService2); // new counters change
EXPECT_EQ(2, sServiceDied2);
+
+ // The service handles are now stale, verify that we can't register a death notification.
+ {
+ std::atomic_int32_t postDied = 0;
+ // we cannot register death notification so handles are null.
+ auto handle1 = mediautils::requestDeathNotification(stale_service, [&] { ++postDied; });
+ EXPECT_FALSE(handle1);
+ auto handle2= mediautils::requestDeathNotification(stale_service2, [&] { ++postDied; });
+ EXPECT_FALSE(handle2);
+ EXPECT_EQ(0, postDied); // no callbacks issued.
+ }
}
diff --git a/services/audioflinger/Android.bp b/services/audioflinger/Android.bp
index 01bde42..add8a43 100644
--- a/services/audioflinger/Android.bp
+++ b/services/audioflinger/Android.bp
@@ -149,7 +149,7 @@
"audio-permission-aidl-cpp",
"audioclient-types-aidl-cpp",
"audioflinger-aidl-cpp",
- "audiopermissioncontroller",
+ "libaudiopermission",
"av-types-aidl-cpp",
"com.android.media.audio-aconfig-cc",
"com.android.media.audioserver-aconfig-cc",
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index b2edaf7..c67fa13 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -110,10 +110,6 @@
static constexpr char kAudioServiceName[] = "audio";
-// In order to avoid invalidating offloaded tracks each time a Visualizer is turned on and off
-// we define a minimum time during which a global effect is considered enabled.
-static const nsecs_t kMinGlobalEffectEnabletimeNs = seconds(7200);
-
// Keep a strong reference to media.log service around forever.
// The service is within our parent process so it can never die in a way that we could observe.
// These two variables are const after initialization.
@@ -5019,11 +5015,6 @@
bool AudioFlinger::isNonOffloadableGlobalEffectEnabled_l() const
{
- if (mGlobalEffectEnableTime != 0 &&
- ((systemTime() - mGlobalEffectEnableTime) < kMinGlobalEffectEnabletimeNs)) {
- return true;
- }
-
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
const auto thread = mPlaybackThreads.valueAt(i);
audio_utils::lock_guard l(thread->mutex());
@@ -5039,8 +5030,6 @@
{
audio_utils::lock_guard _l(mutex());
- mGlobalEffectEnableTime = systemTime();
-
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
const sp<IAfPlaybackThread> t = mPlaybackThreads.valueAt(i);
if (t->type() == IAfThreadBase::OFFLOAD) {
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 133410e..e99c3ed 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -775,9 +775,6 @@
std::atomic<size_t> mClientSharedHeapSize = kMinimumClientSharedHeapSizeBytes;
static constexpr size_t kMinimumClientSharedHeapSizeBytes = 1024 * 1024; // 1MB
- // when a global effect was last enabled
- nsecs_t mGlobalEffectEnableTime GUARDED_BY(mutex()) = 0;
-
/* const */ sp<IAfPatchPanel> mPatchPanel;
const sp<EffectsFactoryHalInterface> mEffectsFactoryHal =
diff --git a/services/audioflinger/IAfThread.h b/services/audioflinger/IAfThread.h
index 3163d4c..8fef263 100644
--- a/services/audioflinger/IAfThread.h
+++ b/services/audioflinger/IAfThread.h
@@ -163,6 +163,7 @@
virtual audio_channel_mask_t mixerChannelMask() const = 0;
virtual audio_format_t format() const = 0;
virtual uint32_t channelCount() const = 0;
+ virtual std::string flagsAsString() const = 0;
// Called by AudioFlinger::frameCount(audio_io_handle_t output) and effects,
// and returns the [normal mix] buffer's frame count.
diff --git a/services/audioflinger/IAfTrack.h b/services/audioflinger/IAfTrack.h
index d27d52a..c9c766f 100644
--- a/services/audioflinger/IAfTrack.h
+++ b/services/audioflinger/IAfTrack.h
@@ -205,6 +205,7 @@
virtual const char* getTrackStateAsString() const = 0;
+ virtual const std::string& getTraceSuffix() const = 0;
// Called by the PlaybackThread to indicate that the track is becoming active
// and a new interval should start with a given device list.
virtual void logBeginInterval(const std::string& devices) = 0;
@@ -212,6 +213,9 @@
// Called by the PlaybackThread to indicate the track is no longer active.
virtual void logEndInterval() = 0;
+ // Called by the PlaybackThread when ATRACE is enabled.
+ virtual void logRefreshInterval(const std::string& devices) = 0;
+
// Called to tally underrun frames in playback.
virtual void tallyUnderrunFrames(size_t frames) = 0;
diff --git a/services/audioflinger/MmapTracks.h b/services/audioflinger/MmapTracks.h
index 0210bc2..259136b 100644
--- a/services/audioflinger/MmapTracks.h
+++ b/services/audioflinger/MmapTracks.h
@@ -78,6 +78,7 @@
float getPortVolume() const override { return mVolume; }
bool getPortMute() const override { return mMutedFromPort; }
+ std::string trackFlagsAsString() const final { return {}; }
private:
DISALLOW_COPY_AND_ASSIGN(MmapTrack);
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 2c3212c..c335c70 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -231,6 +231,8 @@
float getPortVolume() const override { return mVolume; }
bool getPortMute() const override { return mMutedFromPort; }
+ std::string trackFlagsAsString() const final { return toString(mFlags); }
+
protected:
DISALLOW_COPY_AND_ASSIGN(Track);
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index 83cd024..000244e 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -98,6 +98,8 @@
return mResamplerBufferProvider;
}
+ std::string trackFlagsAsString() const final { return toString(mFlags); }
+
private:
DISALLOW_COPY_AND_ASSIGN(RecordTrack);
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 200175b..32690ff 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -33,6 +33,7 @@
#include <afutils/Vibrator.h>
#include <audio_utils/MelProcessor.h>
#include <audio_utils/Metadata.h>
+#include <audio_utils/Trace.h>
#include <com_android_media_audioserver.h>
#ifdef DEBUG_CPU_USAGE
#include <audio_utils/Statistics.h>
@@ -612,7 +613,7 @@
// ----------------------------------------------------------------------------
// static
-const char* ThreadBase::threadTypeToString(ThreadBase::type_t type)
+const char* IAfThreadBase::threadTypeToString(ThreadBase::type_t type)
{
switch (type) {
case MIXER:
@@ -2184,6 +2185,7 @@
mIsTimestampAdvancing(kMinimumTimeBetweenTimestampChecksNs)
{
snprintf(mThreadName, kThreadNameLength, "AudioOut_%X", id);
+ mFlagsAsString = toString(output->flags);
mNBLogWriter = afThreadCallback->newWriter_l(kLogSize, mThreadName);
// Assumes constructor is called by AudioFlinger with its mutex() held, but
@@ -4271,6 +4273,17 @@
track->updateTeePatches_l();
}
+ // check if traces have been enabled.
+ bool atraceEnabled = ATRACE_ENABLED();
+ if (atraceEnabled != mAtraceEnabled) [[unlikely]] {
+ mAtraceEnabled = atraceEnabled;
+ if (atraceEnabled) {
+ const auto devices = patchSinksToString(&mPatch);
+ for (const auto& track : activeTracks) {
+ track->logRefreshInterval(devices);
+ }
+ }
+ }
// signal actual start of output stream when the render position reported by
// the kernel starts moving.
if (!mHalStarted && ((isSuspended() && (mBytesWritten != 0)) || (!mStandby
@@ -5261,6 +5274,8 @@
fastTrack->mHapticScale = os::HapticScale::none();
fastTrack->mHapticMaxAmplitude = NAN;
fastTrack->mGeneration++;
+ snprintf(fastTrack->mTraceName, sizeof(fastTrack->mTraceName),
+ "%s.0.0.%d", AUDIO_TRACE_PREFIX_AUDIO_TRACK_FRDY, mId);
state->mFastTracksGen++;
state->mTrackMask = 1;
// fast mixer will use the HAL output sink
@@ -5838,6 +5853,9 @@
fastTrack->mHapticScale = track->getHapticScale();
fastTrack->mHapticMaxAmplitude = track->getHapticMaxAmplitude();
fastTrack->mGeneration++;
+ snprintf(fastTrack->mTraceName, sizeof(fastTrack->mTraceName),
+ "%s%s", AUDIO_TRACE_PREFIX_AUDIO_TRACK_FRDY,
+ track->getTraceSuffix().c_str());
state->mTrackMask |= 1 << j;
didModify = true;
// no acknowledgement required for newly active tracks
@@ -5980,11 +5998,9 @@
}
size_t framesReady = track->framesReady();
- if (ATRACE_ENABLED()) {
- // I wish we had formatted trace names
- std::string traceName("nRdy");
- traceName += std::to_string(trackId);
- ATRACE_INT(traceName.c_str(), framesReady);
+ if (ATRACE_ENABLED()) [[unlikely]] {
+ ATRACE_INT(std::string(AUDIO_TRACE_PREFIX_AUDIO_TRACK_NRDY)
+ .append(track->getTraceSuffix()).c_str(), framesReady);
}
if ((framesReady >= minFrames) && track->isReady() &&
!track->isPaused() && !track->isTerminated())
@@ -7011,10 +7027,9 @@
const size_t framesReady = track->framesReady();
const int trackId = track->id();
- if (ATRACE_ENABLED()) {
- std::string traceName("nRdy");
- traceName += std::to_string(trackId);
- ATRACE_INT(traceName.c_str(), framesReady);
+ if (ATRACE_ENABLED()) [[unlikely]] {
+ ATRACE_INT(std::string(AUDIO_TRACE_PREFIX_AUDIO_TRACK_NRDY)
+ .append(track->getTraceSuffix()).c_str(), framesReady);
}
if ((framesReady >= minFrames) && track->isReady() && !track->isPaused() &&
!track->isStopping_2() && !track->isStopped())
@@ -7534,6 +7549,11 @@
continue;
}
+ const size_t framesReady = track->framesReady();
+ if (ATRACE_ENABLED()) [[unlikely]] {
+ ATRACE_INT(std::string(AUDIO_TRACE_PREFIX_AUDIO_TRACK_NRDY)
+ .append(track->getTraceSuffix()).c_str(), framesReady);
+ }
if (track->isPausePending()) {
track->pauseAck();
// It is possible a track might have been flushed or stopped.
@@ -7592,7 +7612,7 @@
// Do not handle new data in this iteration even if track->framesReady()
mixerStatus = MIXER_TRACKS_ENABLED;
}
- } else if (track->framesReady() && track->isReady() &&
+ } else if (framesReady && track->isReady() &&
!track->isPaused() && !track->isTerminated() && !track->isStopping_2()) {
ALOGVV("OffloadThread: track(%d) s=%08x [OK]", track->id(), cblk->mServer);
if (track->fillingStatus() == IAfTrack::FS_FILLED) {
@@ -8237,6 +8257,7 @@
, mBtNrecSuspended(false)
{
snprintf(mThreadName, kThreadNameLength, "AudioIn_%X", id);
+ mFlagsAsString = toString(input->flags);
mNBLogWriter = afThreadCallback->newWriter_l(kLogSize, mThreadName);
if (mInput->audioHwDev != nullptr) {
@@ -8574,7 +8595,6 @@
}
if (invalidate) {
activeTrack->invalidate();
- ALOG_ASSERT(fastTrackToRemove == 0);
fastTrackToRemove = activeTrack;
removeTrack_l(activeTrack);
mActiveTracks.remove(activeTrack);
@@ -8591,6 +8611,18 @@
mActiveTracks.updatePowerState_l(this);
+ // check if traces have been enabled.
+ bool atraceEnabled = ATRACE_ENABLED();
+ if (atraceEnabled != mAtraceEnabled) [[unlikely]] {
+ mAtraceEnabled = atraceEnabled;
+ if (atraceEnabled) {
+ const auto devices = patchSourcesToString(&mPatch);
+ for (const auto& track : activeTracks) {
+ track->logRefreshInterval(devices);
+ }
+ }
+ }
+
updateMetadata_l();
if (allStopped) {
@@ -11172,6 +11204,7 @@
mOutput(output)
{
snprintf(mThreadName, kThreadNameLength, "AudioMmapOut_%X", id);
+ mFlagsAsString = toString(output->flags);
mChannelCount = audio_channel_count_from_out_mask(mChannelMask);
mMasterVolume = afThreadCallback->masterVolume_l();
mMasterMute = afThreadCallback->masterMute_l();
@@ -11515,6 +11548,7 @@
mInput(input)
{
snprintf(mThreadName, kThreadNameLength, "AudioMmapIn_%X", id);
+ mFlagsAsString = toString(input->flags);
mChannelCount = audio_channel_count_from_in_mask(mChannelMask);
}
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 1d6e244..6784341 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -43,7 +43,6 @@
class ThreadBase : public virtual IAfThreadBase, public Thread {
public:
- static const char *threadTypeToString(type_t type);
// ThreadBase_ThreadLoop is a virtual mutex (always nullptr) that
// guards methods and variables that ONLY run and are accessed
@@ -400,6 +399,8 @@
}
}
+ std::string flagsAsString() const final { return mFlagsAsString; }
+
sp<IAfEffectHandle> createEffect_l(
const sp<Client>& client,
const sp<media::IEffectClient>& effectClient,
@@ -681,6 +682,9 @@
ThreadMetrics mThreadMetrics;
const bool mIsOut;
+ std::string mFlagsAsString; // set in constructor.
+ bool mAtraceEnabled GUARDED_BY(ThreadBase_ThreadLoop) = false; // checked in threadLoop.
+
// mThreadBusy is checked under the ThreadBase_Mutex to ensure that
// TrackHandle operations do not proceed while the ThreadBase is busy
// with the track. mThreadBusy is only true if the track is active.
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index cde7fc2..2b3d772 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -22,6 +22,7 @@
#include <afutils/NBAIO_Tee.h>
#include <android-base/macros.h> // DISALLOW_COPY_AND_ASSIGN
+#include <audio_utils/Trace.h>
#include <datapath/TrackMetrics.h>
#include <mediautils/BatteryNotifier.h>
#include <psh_utils/AudioPowerManager.h>
@@ -210,16 +211,16 @@
}
}
+ const std::string& getTraceSuffix() const final { return mTraceSuffix; }
// Called by the PlaybackThread to indicate that the track is becoming active
// and a new interval should start with a given device list.
- void logBeginInterval(const std::string& devices) final {
- mTrackMetrics.logBeginInterval(devices);
- }
+ void logBeginInterval(const std::string& devices) final;
// Called by the PlaybackThread to indicate the track is no longer active.
- void logEndInterval() final {
- mTrackMetrics.logEndInterval();
- }
+ void logEndInterval() final;
+
+ // Called by the PlaybackThread when ATRACE is enabled.
+ void logRefreshInterval(const std::string& devices) final;
// Called to tally underrun frames in playback.
void tallyUnderrunFrames(size_t /* frames */) override {}
@@ -333,6 +334,10 @@
void deferRestartIfDisabled();
virtual void restartIfDisabled() {}
+ virtual std::string trackFlagsAsString() const = 0;
+
+ audio_utils::trace::Object createDeviceIntervalTrace(const std::string& devices);
+
const wp<IAfThreadBase> mThread;
const alloc_type mAllocType;
/*const*/ sp<Client> mClient; // see explanation at ~TrackBase() why not const
@@ -384,6 +389,7 @@
bool mLogForceVolumeUpdate = true; // force volume update to TrackMetrics.
+ audio_utils::trace::Object mLastTrace; // accessed by PlaybackThread or RecordThread
TrackMetrics mTrackMetrics;
bool mServerLatencySupported = false;
@@ -393,6 +399,10 @@
const pid_t mCreatorPid; // can be different from mclient->pid() for instance
// when created by NuPlayer on behalf of a client
+ const std::string mTraceSuffix;
+ const std::string mTraceActionId;
+ const std::string mTraceIntervalId;
+
// If the last track change was notified to the client with readAndClearHasChanged
std::atomic_flag mChangeNotified = ATOMIC_FLAG_INIT;
// RAII object for battery stats book-keeping
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 5fbe48c..78ba24d 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -28,6 +28,7 @@
#include "IAfThread.h"
#include "ResamplerBufferProvider.h"
+#include <audio_utils/StringUtils.h>
#include <audio_utils/minifloat.h>
#include <media/AudioValidator.h>
#include <media/RecordBufferConverter.h>
@@ -124,7 +125,12 @@
mPortId(portId),
mIsInvalid(false),
mTrackMetrics(std::move(metricsId), isOut, clientUid),
- mCreatorPid(creatorPid)
+ mCreatorPid(creatorPid),
+ mTraceSuffix{std::to_string(mPortId).append(".").append(std::to_string(mId))
+ .append(".").append(std::to_string(mThreadIoHandle))},
+ mTraceActionId{std::string(AUDIO_TRACE_PREFIX_AUDIO_TRACK_ACTION).append(mTraceSuffix)},
+ mTraceIntervalId{std::string(AUDIO_TRACE_PREFIX_AUDIO_TRACK_INTERVAL)
+ .append(mTraceSuffix)}
{
const uid_t callingUid = IPCThreadState::self()->getCallingUid();
if (!isAudioServerOrMediaServerUid(callingUid) || clientUid == AUDIO_UID_INVALID) {
@@ -337,6 +343,90 @@
mTrackToken.reset();
}
+audio_utils::trace::Object TrackBase::createDeviceIntervalTrace(const std::string& devices) {
+ audio_utils::trace::Object trace;
+
+ // Please do not modify any items without approval (look at git blame).
+ // Sanitize the device string to remove addresses.
+ std::string plainDevices;
+ if (devices.find(")") != std::string::npos) {
+ auto deviceAddrVector = audio_utils::stringutils::getDeviceAddressPairs(devices);
+ for (const auto& deviceAddr : deviceAddrVector) {
+ // "|" not compatible with ATRACE filtering so we use "+".
+ if (!plainDevices.empty()) plainDevices.append("+");
+ plainDevices.append(deviceAddr.first);
+ }
+ } else {
+ plainDevices = devices;
+ }
+
+ trace // the following key, value pairs should be alphabetical
+ .set(AUDIO_TRACE_OBJECT_KEY_CHANNEL_MASK, static_cast<int32_t>(mChannelMask))
+ .set(AUDIO_TRACE_OBJECT_KEY_CONTENT_TYPE, toString(mAttr.content_type))
+ .set(AUDIO_TRACE_OBJECT_KEY_DEVICES, plainDevices)
+ .set(AUDIO_TRACE_OBJECT_KEY_FLAGS, trackFlagsAsString())
+ .set(AUDIO_TRACE_OBJECT_KEY_FORMAT, IAfThreadBase::formatToString(mFormat))
+ .set(AUDIO_TRACE_OBJECT_KEY_FRAMECOUNT, static_cast<int64_t>(mFrameCount))
+ .set(AUDIO_TRACE_OBJECT_KEY_PID, static_cast<int32_t>(mClient->pid()))
+ .set(AUDIO_TRACE_OBJECT_KEY_SAMPLE_RATE, static_cast<int32_t>(sampleRate()));
+ if (const auto thread = mThread.promote()) {
+ trace // continue in alphabetical order
+ .set(AUDIO_TRACE_PREFIX_THREAD AUDIO_TRACE_OBJECT_KEY_CHANNEL_MASK,
+ static_cast<int32_t>(thread->channelMask()))
+ .set(AUDIO_TRACE_PREFIX_THREAD AUDIO_TRACE_OBJECT_KEY_FLAGS,
+ thread->flagsAsString())
+ .set(AUDIO_TRACE_PREFIX_THREAD AUDIO_TRACE_OBJECT_KEY_FORMAT,
+ IAfThreadBase::formatToString(thread->format()))
+ .set(AUDIO_TRACE_PREFIX_THREAD AUDIO_TRACE_OBJECT_KEY_FRAMECOUNT,
+ static_cast<int64_t>(thread->frameCount()))
+ .set(AUDIO_TRACE_PREFIX_THREAD AUDIO_TRACE_OBJECT_KEY_ID,
+ static_cast<int32_t>(mThreadIoHandle))
+ .set(AUDIO_TRACE_PREFIX_THREAD AUDIO_TRACE_OBJECT_KEY_SAMPLE_RATE,
+ static_cast<int32_t>(thread->sampleRate()))
+ .set(AUDIO_TRACE_PREFIX_THREAD AUDIO_TRACE_OBJECT_KEY_TYPE,
+ IAfThreadBase::threadTypeToString(thread->type()));
+ }
+ trace // continue in alphabetical order
+ .set(AUDIO_TRACE_OBJECT_KEY_UID, static_cast<int32_t>(uid()))
+ .set(AUDIO_TRACE_OBJECT_KEY_USAGE, toString(mAttr.usage));
+ return trace;
+}
+
+void TrackBase::logBeginInterval(const std::string& devices) {
+ mTrackMetrics.logBeginInterval(devices);
+
+ if (ATRACE_ENABLED()) [[unlikely]] {
+ auto trace = createDeviceIntervalTrace(devices);
+ mLastTrace = trace;
+ ATRACE_INSTANT_FOR_TRACK(mTraceIntervalId.c_str(),
+ trace.set(AUDIO_TRACE_OBJECT_KEY_EVENT, AUDIO_TRACE_EVENT_BEGIN_INTERVAL)
+ .toTrace().c_str());
+ }
+}
+
+void TrackBase::logEndInterval() {
+ if (!mLastTrace.empty()) {
+ if (ATRACE_ENABLED()) [[unlikely]] {
+ ATRACE_INSTANT_FOR_TRACK(mTraceIntervalId.c_str(),
+ mLastTrace.set(AUDIO_TRACE_OBJECT_KEY_EVENT, AUDIO_TRACE_EVENT_END_INTERVAL)
+ .toTrace().c_str());
+ }
+ mLastTrace.clear();
+ }
+ mTrackMetrics.logEndInterval();
+}
+
+void TrackBase::logRefreshInterval(const std::string& devices) {
+ if (ATRACE_ENABLED()) [[unlikely]] {
+ if (mLastTrace.empty()) mLastTrace = createDeviceIntervalTrace(devices);
+ auto trace = mLastTrace;
+ ATRACE_INSTANT_FOR_TRACK(mTraceIntervalId.c_str(),
+ trace.set(AUDIO_TRACE_OBJECT_KEY_EVENT,
+ AUDIO_TRACE_EVENT_REFRESH_INTERVAL)
+ .toTrace().c_str());
+ }
+}
+
PatchTrackBase::PatchTrackBase(const sp<ClientProxy>& proxy,
IAfThreadBase* thread, const Timeout& timeout)
: mProxy(proxy)
@@ -1159,6 +1249,12 @@
ALOGV("%s(%d): underrun, framesReady(%zu) < framesDesired(%zd), state: %d",
__func__, mId, buf.mFrameCount, desiredFrames, (int)mState);
mAudioTrackServerProxy->tallyUnderrunFrames(desiredFrames);
+ if (ATRACE_ENABLED()) [[unlikely]] {
+ ATRACE_INSTANT_FOR_TRACK(mTraceActionId.c_str(), audio_utils::trace::Object{}
+ .set(AUDIO_TRACE_OBJECT_KEY_EVENT, AUDIO_TRACE_EVENT_UNDERRUN)
+ .set(AUDIO_TRACE_OBJECT_KEY_FRAMECOUNT, desiredFrames)
+ .toTrace().c_str());
+ }
} else {
mAudioTrackServerProxy->tallyUnderrunFrames(0);
}
@@ -1271,6 +1367,11 @@
status_t Track::start(AudioSystem::sync_event_t event __unused,
audio_session_t triggerSession __unused)
{
+ if (ATRACE_ENABLED()) [[unlikely]] {
+ ATRACE_INSTANT_FOR_TRACK(mTraceActionId.c_str(), audio_utils::trace::Object{}
+ .set(AUDIO_TRACE_OBJECT_KEY_EVENT, AUDIO_TRACE_EVENT_START)
+ .toTrace().c_str());
+ }
status_t status = NO_ERROR;
ALOGV("%s(%d): calling pid %d session %d",
__func__, mId, IPCThreadState::self()->getCallingPid(), mSessionId);
@@ -1415,6 +1516,11 @@
void Track::stop()
{
ALOGV("%s(%d): calling pid %d", __func__, mId, IPCThreadState::self()->getCallingPid());
+ if (ATRACE_ENABLED()) [[unlikely]] {
+ ATRACE_INSTANT_FOR_TRACK(mTraceActionId.c_str(), audio_utils::trace::Object{}
+ .set(AUDIO_TRACE_OBJECT_KEY_EVENT, AUDIO_TRACE_EVENT_STOP)
+ .toTrace().c_str());
+ }
const sp<IAfThreadBase> thread = mThread.promote();
if (thread != 0) {
audio_utils::unique_lock ul(thread->mutex());
@@ -1452,6 +1558,11 @@
void Track::pause()
{
ALOGV("%s(%d): calling pid %d", __func__, mId, IPCThreadState::self()->getCallingPid());
+ if (ATRACE_ENABLED()) [[unlikely]] {
+ ATRACE_INSTANT_FOR_TRACK(mTraceActionId.c_str(), audio_utils::trace::Object{}
+ .set(AUDIO_TRACE_OBJECT_KEY_EVENT, AUDIO_TRACE_EVENT_PAUSE)
+ .toTrace().c_str());
+ }
const sp<IAfThreadBase> thread = mThread.promote();
if (thread != 0) {
audio_utils::unique_lock ul(thread->mutex());
@@ -1491,6 +1602,11 @@
void Track::flush()
{
ALOGV("%s(%d)", __func__, mId);
+ if (ATRACE_ENABLED()) [[unlikely]] {
+ ATRACE_INSTANT_FOR_TRACK(mTraceActionId.c_str(), audio_utils::trace::Object{}
+ .set(AUDIO_TRACE_OBJECT_KEY_EVENT, AUDIO_TRACE_EVENT_FLUSH)
+ .toTrace().c_str());
+ }
const sp<IAfThreadBase> thread = mThread.promote();
if (thread != 0) {
audio_utils::unique_lock ul(thread->mutex());
@@ -2936,6 +3052,11 @@
status_t RecordTrack::start(AudioSystem::sync_event_t event,
audio_session_t triggerSession)
{
+ if (ATRACE_ENABLED()) [[unlikely]] {
+ ATRACE_INSTANT_FOR_TRACK(mTraceActionId.c_str(), audio_utils::trace::Object{}
+ .set(AUDIO_TRACE_OBJECT_KEY_EVENT, AUDIO_TRACE_EVENT_START)
+ .toTrace().c_str());
+ }
const sp<IAfThreadBase> thread = mThread.promote();
if (thread != 0) {
auto* const recordThread = thread->asIAfRecordThread().get();
@@ -2948,6 +3069,11 @@
void RecordTrack::stop()
{
+ if (ATRACE_ENABLED()) [[unlikely]] {
+ ATRACE_INSTANT_FOR_TRACK(mTraceActionId.c_str(), audio_utils::trace::Object{}
+ .set(AUDIO_TRACE_OBJECT_KEY_EVENT, AUDIO_TRACE_EVENT_STOP)
+ .toTrace().c_str());
+ }
const sp<IAfThreadBase> thread = mThread.promote();
if (thread != 0) {
auto* const recordThread = thread->asIAfRecordThread().get();
@@ -3619,11 +3745,21 @@
status_t MmapTrack::start(AudioSystem::sync_event_t event __unused,
audio_session_t triggerSession __unused)
{
+ if (ATRACE_ENABLED()) [[unlikely]] {
+ ATRACE_INSTANT_FOR_TRACK(mTraceActionId.c_str(), audio_utils::trace::Object{}
+ .set(AUDIO_TRACE_OBJECT_KEY_EVENT, AUDIO_TRACE_EVENT_START)
+ .toTrace().c_str());
+ }
return NO_ERROR;
}
void MmapTrack::stop()
{
+ if (ATRACE_ENABLED()) [[unlikely]] {
+ ATRACE_INSTANT_FOR_TRACK(mTraceActionId.c_str(), audio_utils::trace::Object{}
+ .set(AUDIO_TRACE_OBJECT_KEY_EVENT, AUDIO_TRACE_EVENT_STOP)
+ .toTrace().c_str());
+ }
}
// AudioBufferProvider interface
diff --git a/services/audioflinger/fastpath/FastMixer.cpp b/services/audioflinger/fastpath/FastMixer.cpp
index 1d41b3f..760ce1d 100644
--- a/services/audioflinger/fastpath/FastMixer.cpp
+++ b/services/audioflinger/fastpath/FastMixer.cpp
@@ -36,6 +36,7 @@
#include <cpustats/ThreadCpuUsage.h>
#endif
#endif
+#include <audio_utils/Trace.h>
#include <audio_utils/channels.h>
#include <audio_utils/format.h>
#include <audio_utils/mono_blend.h>
@@ -397,12 +398,7 @@
// in the overall fast mix cycle being delayed. Should use a non-blocking FIFO.
const size_t framesReady = fastTrack->mBufferProvider->framesReady();
if (ATRACE_ENABLED()) {
- // I wish we had formatted trace names
- char traceName[16];
- strcpy(traceName, "fRdy");
- traceName[4] = i + (i < 10 ? '0' : 'A' - 10);
- traceName[5] = '\0';
- ATRACE_INT(traceName, framesReady);
+ ATRACE_INT(fastTrack->mTraceName, framesReady);
}
FastTrackDump *ftDump = &dumpState->mTracks[i];
FastTrackUnderruns underruns = ftDump->mUnderruns;
diff --git a/services/audioflinger/fastpath/FastMixerState.h b/services/audioflinger/fastpath/FastMixerState.h
index 0a56f92..f01dd4b 100644
--- a/services/audioflinger/fastpath/FastMixerState.h
+++ b/services/audioflinger/fastpath/FastMixerState.h
@@ -56,6 +56,7 @@
bool mHapticPlaybackEnabled = false; // haptic playback is enabled or not
os::HapticScale mHapticScale = os::HapticScale::mute(); // scale of haptic data
float mHapticMaxAmplitude = NAN; // max amplitude allowed for haptic data
+ char mTraceName[32]{};
};
// No virtuals.
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 8dd247a..e5bd121 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -19,15 +19,18 @@
#include <android/media/DeviceConnectedState.h>
#include <android/media/TrackInternalMuteInfo.h>
+#include <android/media/audio/common/AudioConfigBase.h>
#include <android/media/audio/common/AudioMMapPolicyInfo.h>
#include <android/media/audio/common/AudioMMapPolicyType.h>
+#include <android/media/GetInputForAttrResponse.h>
+#include <android/content/AttributionSourceState.h>
+#include <error/BinderResult.h>
#include <media/AudioCommonTypes.h>
#include <media/AudioContainers.h>
#include <media/AudioDeviceTypeAddr.h>
-#include <media/AudioSystem.h>
#include <media/AudioPolicy.h>
+#include <media/AudioSystem.h>
#include <media/DeviceDescriptorBase.h>
-#include <android/content/AttributionSourceState.h>
#include <utils/String8.h>
namespace android {
@@ -161,18 +164,26 @@
// releases the output, return true if the output descriptor is reopened.
virtual bool releaseOutput(audio_port_handle_t portId) = 0;
- // request an input appropriate for record from the supplied device with supplied parameters.
- virtual status_t getInputForAttr(const audio_attributes_t *attr,
- audio_io_handle_t *input,
+ // Request an input appropriate for record from the supplied device with supplied parameters.
+ // attr -- attributes for the requested record
+ // requestedInput -- input only for MMAP mode where an input is re-used, otherwise output param
+ // requestedDeviceId, config, flags -- additional params for matching
+ // riid, session, attributionSource -- params which encapsulate client info to associate with
+ // this input
+ //
+ // On most errors, return a Status describing the error in the error object.
+ // However, in cases where an appropriate device cannot be found for a config, the error side of
+ // the unexpected will contain a suggested config.
+ virtual base::expected<media::GetInputForAttrResponse,
+ std::variant<binder::Status, media::audio::common::AudioConfigBase>>
+ getInputForAttr(audio_attributes_t attributes,
+ audio_io_handle_t requestedInput,
+ audio_port_handle_t requestedDeviceId,
+ audio_config_base_t config,
+ audio_input_flags_t flags,
audio_unique_id_t riid,
audio_session_t session,
- const AttributionSourceState& attributionSource,
- audio_config_base_t *config,
- audio_input_flags_t flags,
- audio_port_handle_t *selectedDeviceId,
- input_type_t *inputType,
- audio_port_handle_t *portId,
- uint32_t *virtualDeviceId) = 0;
+ const AttributionSourceState& attributionSource) = 0;
// indicates to the audio policy manager that the input starts being used.
virtual status_t startInput(audio_port_handle_t portId) = 0;
// indicates to the audio policy manager that the input stops being used.
@@ -625,6 +636,32 @@
virtual status_t getMmapPolicyInfos(
media::audio::common::AudioMMapPolicyType policyType,
std::vector<media::audio::common::AudioMMapPolicyInfo> *policyInfos) = 0;
+
+ enum class MixType {
+ // e.g. audio recording from a microphone
+ NONE = 0,
+ // used for "remote submix" legacy mode (no DAP), capture of the media to play it remotely
+ CAPTURE,
+ // used for platform audio rerouting, where mixes are handled by external and dynamically
+ // installed policies which reroute audio mixes
+ EXT_POLICY_REROUTE,
+ // used for playback capture with a MediaProjection
+ PUBLIC_CAPTURE_PLAYBACK,
+ // used for capture from telephony RX path
+ TELEPHONY_RX_CAPTURE,
+ };
+
+ struct PermissionReqs {
+ media::audio::common::AudioSource source;
+ MixType mixType;
+ uint32_t virtualDeviceId;
+ // Flag based validation
+ bool isHotword;
+ bool isCallRedir;
+ };
+
+ virtual error::BinderResult<bool> checkPermissionForInput(const AttributionSourceState& attr,
+ const PermissionReqs& req) = 0;
};
// These are the signatures of createAudioPolicyManager/destroyAudioPolicyManager
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h b/services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h
index e519766..918e247 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h
@@ -64,6 +64,21 @@
if (activeClients.size() == activeClientsWithRoute.size()) {
return devices.getDeviceFromId(activeClientsWithRoute[0]->preferredDeviceId());
}
+ if (activeClientsWithRoute.size() == 0) {
+ return nullptr;
+ }
+ uid_t uniqueUid = activeClients[0]->uid();
+ for (const auto &client : activeClients) {
+ if (uniqueUid != client->uid()) {
+ return nullptr;
+ }
+ }
+ for (const auto &client : activeClientsWithRoute) {
+ if (uniqueUid != client->uid()) {
+ return nullptr;
+ }
+ }
+ return devices.getDeviceFromId(activeClientsWithRoute[0]->preferredDeviceId());
}
}
return nullptr;
diff --git a/services/audiopolicy/engineconfigurable/config/example/common/audio_policy_engine_criterion_types_aidl.xml.in b/services/audiopolicy/engineconfigurable/config/example/common/audio_policy_engine_criterion_types_aidl.xml.in
index dc2517b..424c983 100644
--- a/services/audiopolicy/engineconfigurable/config/example/common/audio_policy_engine_criterion_types_aidl.xml.in
+++ b/services/audiopolicy/engineconfigurable/config/example/common/audio_policy_engine_criterion_types_aidl.xml.in
@@ -19,76 +19,77 @@
<criterion_type name="OutputDevicesAddressesType" type="inclusive">
<values>
<!-- legacy remote submix -->
- <value literal="0" numerical="1"/>
+ <value literal="0"/>
</values>
</criterion_type>
<criterion_type name="InputDevicesAddressesType" type="inclusive">
<values>
<!-- legacy remote submix -->
- <value literal="0" numerical="1"/>
+ <value literal="0"/>
</values>
</criterion_type>
<criterion_type name="AndroidModeType" type="exclusive"/>
<criterion_type name="ForceUseForCommunicationType" type="exclusive">
<values>
- <value literal="NONE" numerical="0"/>
- <value literal="SPEAKER" numerical="1"/>
- <value literal="BT_SCO" numerical="3"/>
+ <value literal="NONE"/>
+ <value literal="SPEAKER"/>
+ <value literal="BT_SCO"/>
</values>
</criterion_type>
<criterion_type name="ForceUseForMediaType" type="exclusive">
<values>
- <value literal="NONE" numerical="0"/>
- <value literal="SPEAKER" numerical="1"/>
- <value literal="HEADPHONES" numerical="2"/>
- <value literal="BT_A2DP" numerical="4"/>
- <value literal="WIRED_ACCESSORY" numerical="5"/>
- <value literal="ANALOG_DOCK" numerical="8"/>
- <value literal="DIGITAL_DOCK" numerical="9"/>
- <value literal="NO_BT_A2DP" numerical="10"/>
+ <value literal="NONE"/>
+ <value literal="SPEAKER"/>
+ <value literal="HEADPHONES"/>
+ <value literal="BT_A2DP"/>
+ <value literal="ANALOG_DOCK"/>
+ <value literal="DIGITAL_DOCK"/>
+ <value literal="WIRED_ACCESSORY"/>
+ <value literal="NO_BT_A2DP"/>
</values>
</criterion_type>
<criterion_type name="ForceUseForRecordType" type="exclusive">
<values>
- <value literal="NONE" numerical="0"/>
- <value literal="BT_SCO" numerical="3"/>
- <value literal="WIRED_ACCESSORY" numerical="5"/>
+ <value literal="NONE"/>
+ <value literal="BT_SCO"/>
+ <value literal="WIRED_ACCESSORY"/>
</values>
</criterion_type>
<criterion_type name="ForceUseForDockType" type="exclusive">
<values>
- <value literal="NONE" numerical="0"/>
- <value literal="WIRED_ACCESSORY" numerical="5"/>
- <value literal="BT_CAR_DOCK" numerical="6"/>
- <value literal="BT_DESK_DOCK" numerical="7"/>
- <value literal="ANALOG_DOCK" numerical="8"/>
- <value literal="DIGITAL_DOCK" numerical="9"/>
+ <value literal="NONE"/>
+ <value literal="BT_CAR_DOCK"/>
+ <value literal="BT_DESK_DOCK"/>
+ <value literal="ANALOG_DOCK"/>
+ <value literal="DIGITAL_DOCK"/>
+ <value literal="WIRED_ACCESSORY"/>
</values>
</criterion_type>
<criterion_type name="ForceUseForSystemType" type="exclusive" >
<values>
- <value literal="NONE" numerical="0"/>
- <value literal="SYSTEM_ENFORCED" numerical="11"/>
+ <value literal="NONE"/>
+ <value literal="SYSTEM_ENFORCED"/>
</values>
</criterion_type>
<criterion_type name="ForceUseForHdmiSystemAudioType" type="exclusive">
<values>
- <value literal="NONE" numerical="0"/>
- <value literal="HDMI_SYSTEM_AUDIO_ENFORCED" numerical="12"/>
+ <value literal="NONE"/>
+ <value literal="HDMI_SYSTEM_AUDIO_ENFORCED"/>
</values>
</criterion_type>
<criterion_type name="ForceUseForEncodedSurroundType" type="exclusive">
<values>
- <value literal="NONE" numerical="0"/>
- <value literal="ENCODED_SURROUND_NEVER" numerical="13"/>
- <value literal="ENCODED_SURROUND_ALWAYS" numerical="14"/>
- <value literal="ENCODED_SURROUND_MANUAL" numerical="15"/>
+ <value literal="UNSPECIFIED"/>
+ <value literal="NEVER"/>
+ <value literal="ALWAYS"/>
+ <value literal="MANUAL"/>
</values>
</criterion_type>
<criterion_type name="ForceUseForVibrateRingingType" type="exclusive">
<values>
- <value literal="NONE" numerical="0"/>
- <value literal="BT_SCO" numerical="3"/>
+ <value literal="NONE"/>
+ <value literal="BT_SCO"/>
+ <value literal="BT_BLE"/>
</values>
</criterion_type>
</criterion_types>
diff --git a/services/audiopolicy/engineconfigurable/config/src/CapEngineConfig.cpp b/services/audiopolicy/engineconfigurable/config/src/CapEngineConfig.cpp
index b72e517..b89fba0 100644
--- a/services/audiopolicy/engineconfigurable/config/src/CapEngineConfig.cpp
+++ b/services/audiopolicy/engineconfigurable/config/src/CapEngineConfig.cpp
@@ -41,21 +41,23 @@
namespace android {
-using utilities::convertTo;
+using base::unexpected;
using media::audio::common::AudioDeviceAddress;
using media::audio::common::AudioDeviceDescription;
using media::audio::common::AudioHalCapCriterion;
+using media::audio::common::AudioHalCapCriterionV2;
using media::audio::common::AudioHalCapParameter;
using media::audio::common::AudioHalCapRule;
+using media::audio::common::AudioPolicyForceUse;
using media::audio::common::AudioSource;
using media::audio::common::AudioStreamType;
-using media::audio::common::AudioHalCapCriterionV2;
-using ::android::base::unexpected;
+using utilities::convertTo;
namespace capEngineConfig {
static constexpr const char *gLegacyOutputDevicePrefix = "AUDIO_DEVICE_OUT_";
static constexpr const char *gLegacyInputDevicePrefix = "AUDIO_DEVICE_IN_";
+static constexpr const char *gLegacyForcePrefix = "AUDIO_POLICY_FORCE_";
static constexpr const char *gLegacyStreamPrefix = "AUDIO_STREAM_";
static constexpr const char *gLegacySourcePrefix = "AUDIO_SOURCE_";
static constexpr const char *gPolicyParamPrefix = "/Policy/policy/";
@@ -83,6 +85,134 @@
return capName;
}
+ConversionResult<audio_policy_forced_cfg_t>
+ aidl2legacy_AudioPolicyForceUseCommunicationDeviceCategory_audio_policy_forced_cfg_t(
+ const AudioPolicyForceUse::CommunicationDeviceCategory aidl) {
+ switch (aidl) {
+ case AudioPolicyForceUse::CommunicationDeviceCategory::NONE:
+ return AUDIO_POLICY_FORCE_NONE;
+ case AudioPolicyForceUse::CommunicationDeviceCategory::SPEAKER:
+ return AUDIO_POLICY_FORCE_SPEAKER;
+ case AudioPolicyForceUse::CommunicationDeviceCategory::BT_SCO:
+ return AUDIO_POLICY_FORCE_BT_SCO;
+ case AudioPolicyForceUse::CommunicationDeviceCategory::BT_BLE:
+ return AUDIO_POLICY_FORCE_BT_BLE;
+ case AudioPolicyForceUse::CommunicationDeviceCategory::WIRED_ACCESSORY:
+ return AUDIO_POLICY_FORCE_WIRED_ACCESSORY;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<audio_policy_forced_cfg_t>
+ aidl2legacy_AudioPolicyForceUseMediaDeviceCategory_audio_policy_forced_cfg_t(
+ const AudioPolicyForceUse::MediaDeviceCategory aidl) {
+ switch (aidl) {
+ case AudioPolicyForceUse::MediaDeviceCategory::NONE:
+ return AUDIO_POLICY_FORCE_NONE;
+ case AudioPolicyForceUse::MediaDeviceCategory::SPEAKER:
+ return AUDIO_POLICY_FORCE_SPEAKER;
+ case AudioPolicyForceUse::MediaDeviceCategory::HEADPHONES:
+ return AUDIO_POLICY_FORCE_HEADPHONES;
+ case AudioPolicyForceUse::MediaDeviceCategory::BT_A2DP:
+ return AUDIO_POLICY_FORCE_BT_A2DP;
+ case AudioPolicyForceUse::MediaDeviceCategory::ANALOG_DOCK:
+ return AUDIO_POLICY_FORCE_ANALOG_DOCK;
+ case AudioPolicyForceUse::MediaDeviceCategory::DIGITAL_DOCK:
+ return AUDIO_POLICY_FORCE_DIGITAL_DOCK;
+ case AudioPolicyForceUse::MediaDeviceCategory::WIRED_ACCESSORY:
+ return AUDIO_POLICY_FORCE_WIRED_ACCESSORY;
+ case AudioPolicyForceUse::MediaDeviceCategory::NO_BT_A2DP:
+ return AUDIO_POLICY_FORCE_NO_BT_A2DP;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<audio_policy_forced_cfg_t>
+ aidl2legacy_AudioPolicyForceUseDockType_audio_policy_forced_cfg_t(
+ const AudioPolicyForceUse::DockType aidl) {
+ switch (aidl) {
+ case AudioPolicyForceUse::DockType::NONE:
+ return AUDIO_POLICY_FORCE_NONE;
+ case AudioPolicyForceUse::DockType::BT_CAR_DOCK:
+ return AUDIO_POLICY_FORCE_BT_CAR_DOCK;
+ case AudioPolicyForceUse::DockType::BT_DESK_DOCK:
+ return AUDIO_POLICY_FORCE_BT_DESK_DOCK;
+ case AudioPolicyForceUse::DockType::ANALOG_DOCK:
+ return AUDIO_POLICY_FORCE_ANALOG_DOCK;
+ case AudioPolicyForceUse::DockType::DIGITAL_DOCK:
+ return AUDIO_POLICY_FORCE_DIGITAL_DOCK;
+ case AudioPolicyForceUse::DockType::WIRED_ACCESSORY:
+ return AUDIO_POLICY_FORCE_WIRED_ACCESSORY;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<audio_policy_forced_cfg_t>
+ aidl2legacy_AudioPolicyForceUseEncodedSurroundConfig_audio_policy_forced_cfg_t(
+ const AudioPolicyForceUse::EncodedSurroundConfig aidl) {
+ switch (aidl) {
+ case AudioPolicyForceUse::EncodedSurroundConfig::UNSPECIFIED:
+ return AUDIO_POLICY_FORCE_NONE;
+ case AudioPolicyForceUse::EncodedSurroundConfig::NEVER:
+ return AUDIO_POLICY_FORCE_ENCODED_SURROUND_NEVER;
+ case AudioPolicyForceUse::EncodedSurroundConfig::ALWAYS:
+ return AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS;
+ case AudioPolicyForceUse::EncodedSurroundConfig::MANUAL:
+ return AUDIO_POLICY_FORCE_ENCODED_SURROUND_MANUAL;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<std::pair<audio_policy_force_use_t, audio_policy_forced_cfg_t>>
+ aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t_audio_policy_forced_cfg_t(
+ const AudioPolicyForceUse& aidl) {
+ switch (aidl.getTag()) {
+ case AudioPolicyForceUse::forCommunication:
+ return std::make_pair(
+ AUDIO_POLICY_FORCE_FOR_COMMUNICATION,
+ VALUE_OR_RETURN(
+ aidl2legacy_AudioPolicyForceUseCommunicationDeviceCategory_audio_policy_forced_cfg_t(
+ aidl.get<AudioPolicyForceUse::forCommunication>())));
+ case AudioPolicyForceUse::forMedia:
+ return std::make_pair(
+ AUDIO_POLICY_FORCE_FOR_MEDIA,
+ VALUE_OR_RETURN(
+ aidl2legacy_AudioPolicyForceUseMediaDeviceCategory_audio_policy_forced_cfg_t(
+ aidl.get<AudioPolicyForceUse::forMedia>())));
+ case AudioPolicyForceUse::forRecord:
+ return std::make_pair(
+ AUDIO_POLICY_FORCE_FOR_RECORD,
+ VALUE_OR_RETURN(
+ aidl2legacy_AudioPolicyForceUseCommunicationDeviceCategory_audio_policy_forced_cfg_t(
+ aidl.get<AudioPolicyForceUse::forRecord>())));
+ case AudioPolicyForceUse::dock:
+ return std::make_pair(AUDIO_POLICY_FORCE_FOR_DOCK,
+ VALUE_OR_RETURN(
+ aidl2legacy_AudioPolicyForceUseDockType_audio_policy_forced_cfg_t(
+ aidl.get<AudioPolicyForceUse::dock>())));
+ case AudioPolicyForceUse::systemSounds:
+ return std::make_pair(AUDIO_POLICY_FORCE_FOR_SYSTEM,
+ aidl.get<AudioPolicyForceUse::systemSounds>() ?
+ AUDIO_POLICY_FORCE_SYSTEM_ENFORCED : AUDIO_POLICY_FORCE_NONE);
+ case AudioPolicyForceUse::hdmiSystemAudio:
+ return std::make_pair(
+ AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO,
+ aidl.get<AudioPolicyForceUse::hdmiSystemAudio>() ?
+ AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED : AUDIO_POLICY_FORCE_NONE);
+ case AudioPolicyForceUse::encodedSurround:
+ return std::make_pair(AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND, VALUE_OR_RETURN(
+ aidl2legacy_AudioPolicyForceUseEncodedSurroundConfig_audio_policy_forced_cfg_t(
+ aidl.get<AudioPolicyForceUse::encodedSurround>())));
+ case AudioPolicyForceUse::forVibrateRinging:
+ return std::make_pair(
+ AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING,
+ VALUE_OR_RETURN(
+ aidl2legacy_AudioPolicyForceUseCommunicationDeviceCategory_audio_policy_forced_cfg_t(
+ aidl.get<AudioPolicyForceUse::forVibrateRinging>())));
+ }
+ return unexpected(BAD_VALUE);
+}
+
ConversionResult<std::string> aidl2legacy_AudioHalCapCriterionV2_CapName(
const AudioHalCapCriterionV2& aidl) {
switch (aidl.getTag()) {
@@ -97,14 +227,14 @@
case AudioHalCapCriterionV2::telephonyMode:
return gPhoneStateCriterionName;
case AudioHalCapCriterionV2::forceConfigForUse: {
- auto aidlCriterion = aidl.get<AudioHalCapCriterionV2::forceConfigForUse>();
- return gForceUseCriterionTag[VALUE_OR_RETURN(
- aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t(
- aidlCriterion.forceUse))];
+ auto aidlCriterion = aidl.get<AudioHalCapCriterionV2::forceConfigForUse>().values[0];
+ const auto [forceUse, _] = VALUE_OR_RETURN(
+ aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t_audio_policy_forced_cfg_t(
+ aidlCriterion));
+ return gForceUseCriterionTag[forceUse];
}
- default:
- return unexpected(BAD_VALUE);
}
+ return unexpected(BAD_VALUE);
}
ConversionResult<std::string> aidl2legacy_AudioHalCapCriterionV2TypeDevice_CapCriterionValue(
@@ -121,6 +251,32 @@
isOut ? gLegacyOutputDevicePrefix : gLegacyInputDevicePrefix);
}
+ConversionResult<audio_policy_forced_cfg_t>
+ aidl2legacy_AudioHalCapCriterionV2ForceUse_audio_policy_forced_cfg_t(
+ const AudioPolicyForceUse& aidl) {
+ const auto [_, legacyForcedCfg] = VALUE_OR_RETURN(
+ aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t_audio_policy_forced_cfg_t(
+ aidl));
+ return legacyForcedCfg;
+}
+
+ConversionResult<std::string> audio_policy_forced_cfg_t_CapCriterionValue(
+ audio_policy_forced_cfg_t legacyForcedCfg) {
+ std::string legacyForcedCfgLiteral = audio_policy_forced_cfg_to_string(legacyForcedCfg);
+ if (legacyForcedCfgLiteral.empty()) {
+ ALOGE("%s Invalid forced config value %d", __func__, legacyForcedCfg);
+ return unexpected(BAD_VALUE);
+ }
+ return truncatePrefix(legacyForcedCfgLiteral, gLegacyForcePrefix);
+}
+
+ConversionResult<std::string> aidl2legacy_AudioHalCapCriterionV2ForceUse_CapCriterionValue(
+ const AudioPolicyForceUse& aidl) {
+ const audio_policy_forced_cfg_t legacyForcedCfg = VALUE_OR_RETURN(
+ aidl2legacy_AudioHalCapCriterionV2ForceUse_audio_policy_forced_cfg_t(aidl));
+ return audio_policy_forced_cfg_t_CapCriterionValue(legacyForcedCfg);
+}
+
ConversionResult<std::string> aidl2legacy_AudioHalCapCriterionV2Type_CapCriterionValue(
const AudioHalCapCriterionV2& aidl) {
switch (aidl.getTag()) {
@@ -139,10 +295,10 @@
case AudioHalCapCriterionV2::telephonyMode:
return toString(aidl.get<AudioHalCapCriterionV2::telephonyMode>().values[0]);
case AudioHalCapCriterionV2::forceConfigForUse:
- return toString(aidl.get<AudioHalCapCriterionV2::forceConfigForUse>().values[0]);
- default:
- return unexpected(BAD_VALUE);
+ return aidl2legacy_AudioHalCapCriterionV2ForceUse_CapCriterionValue(
+ aidl.get<AudioHalCapCriterionV2::forceConfigForUse>().values[0]);
}
+ return unexpected(BAD_VALUE);
}
ConversionResult<std::string> aidl2legacy_AudioHalCapRule_CapRule(
@@ -331,24 +487,28 @@
engineConfig::Criterion& criterion = capCriterion.criterion;
engineConfig::CriterionType& criterionType = capCriterion.criterionType;
- auto loadForceUseCriterion = [](const auto &aidlCriterion, auto &criterion,
- auto &criterionType) -> status_t {
- uint32_t legacyForceUse = VALUE_OR_RETURN_STATUS(
- aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t(
- aidlCriterion.forceUse));
+ auto loadForceUseCriterion = [](const auto& aidlCriterion, auto& criterion,
+ auto& criterionType) -> status_t {
+ if (aidlCriterion.values.empty()) {
+ return BAD_VALUE;
+ }
+ const auto [legacyForceUse, _] = VALUE_OR_RETURN_STATUS(
+ aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t_audio_policy_forced_cfg_t(
+ aidlCriterion.values[0]));
criterion.typeName = criterionType.name;
criterionType.name = criterion.typeName + gCriterionTypeSuffix;
criterionType.isInclusive =
(aidlCriterion.logic == AudioHalCapCriterionV2::LogicalDisjunction::INCLUSIVE);
criterion.name = gForceUseCriterionTag[legacyForceUse];
- criterion.defaultLiteralValue = toString(aidlCriterion.defaultValue);
- if (aidlCriterion.values.empty()) {
- return BAD_VALUE;
- }
+ criterion.defaultLiteralValue = toString(
+ aidlCriterion.defaultValue.template get<AudioPolicyForceUse::forMedia>());
for (auto &value : aidlCriterion.values) {
- uint32_t legacyForcedConfig = VALUE_OR_RETURN_STATUS(
- aidl2legacy_AudioPolicyForcedConfig_audio_policy_forced_cfg_t(value));
- criterionType.valuePairs.push_back({legacyForcedConfig, 0, toString(value)});
+ const audio_policy_forced_cfg_t legacyForcedCfg = VALUE_OR_RETURN_STATUS(
+ aidl2legacy_AudioHalCapCriterionV2ForceUse_audio_policy_forced_cfg_t(value));
+ const std::string legacyForcedCfgLiteral = VALUE_OR_RETURN_STATUS(
+ audio_policy_forced_cfg_t_CapCriterionValue(legacyForcedCfg));
+ criterionType.valuePairs.push_back(
+ {legacyForcedCfg, 0, legacyForcedCfgLiteral});
}
return NO_ERROR;
};
diff --git a/services/audiopolicy/engineconfigurable/tools/capBuildPolicyCriterionTypes.py b/services/audiopolicy/engineconfigurable/tools/capBuildPolicyCriterionTypes.py
index b873830..1adc602 100755
--- a/services/audiopolicy/engineconfigurable/tools/capBuildPolicyCriterionTypes.py
+++ b/services/audiopolicy/engineconfigurable/tools/capBuildPolicyCriterionTypes.py
@@ -102,7 +102,6 @@
ordered_values = OrderedDict(sorted(values_dict.items(), key=lambda x: x[1]))
for key, value in ordered_values.items():
value_node = ET.SubElement(values_node, "value")
- value_node.set('numerical', str(value))
value_node.set('literal', key)
if criterion_type.get('name') == "OutputDevicesMaskType":
@@ -114,20 +113,14 @@
for criterion_name, values_list in addressCriteria.items():
for criterion_type in criterion_types_root.findall('criterion_type'):
if criterion_type.get('name') == criterion_name:
- index = 0
existing_values_node = criterion_type.find("values")
if existing_values_node is not None:
- for existing_value in existing_values_node.findall('value'):
- if existing_value.get('numerical') == str(1 << index):
- index += 1
values_node = existing_values_node
else:
values_node = ET.SubElement(criterion_type, "values")
for value in values_list:
value_node = ET.SubElement(values_node, "value", literal=value)
- value_node.set('numerical', str(1 << index))
- index += 1
xmlstr = ET.tostring(criterion_types_root, encoding='utf8', method='xml')
reparsed = MINIDOM.parseString(xmlstr)
diff --git a/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp b/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
index 1c6248a..b17a248 100644
--- a/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
+++ b/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
@@ -286,7 +286,7 @@
bool AudioPolicyManagerFuzzer::getInputForAttr(
const audio_attributes_t &attr, audio_unique_id_t riid, audio_port_handle_t *selectedDeviceId,
audio_format_t format, audio_channel_mask_t channelMask, int sampleRate,
- audio_input_flags_t flags, audio_port_handle_t *portId, uint32_t *virtualDeviceId) {
+ audio_input_flags_t flags, audio_port_handle_t *portId, uint32_t*) {
audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
audio_config_base_t config = AUDIO_CONFIG_BASE_INITIALIZER;
config.sample_rate = sampleRate;
@@ -295,16 +295,15 @@
audio_port_handle_t localPortId;
if (!portId) portId = &localPortId;
*portId = AUDIO_PORT_HANDLE_NONE;
- AudioPolicyInterface::input_type_t inputType;
AttributionSourceState attributionSource;
attributionSource.uid = 0;
attributionSource.token = sp<BBinder>::make();
- if (mManager->getInputForAttr(&attr, &input, riid, AUDIO_SESSION_NONE, attributionSource,
- &config, flags, selectedDeviceId, &inputType, portId, virtualDeviceId) != OK) {
- return false;
- }
- if (*portId == AUDIO_PORT_HANDLE_NONE || input == AUDIO_IO_HANDLE_NONE) {
+ const auto inputRes = mManager->getInputForAttr(attr, input, *selectedDeviceId, config, flags,
+ riid, AUDIO_SESSION_NONE, attributionSource);
+ if (!inputRes.has_value()) return false;
+
+ if (inputRes->portId == AUDIO_PORT_HANDLE_NONE || inputRes->input == AUDIO_IO_HANDLE_NONE) {
return false;
}
return true;
diff --git a/services/audiopolicy/managerdefault/Android.bp b/services/audiopolicy/managerdefault/Android.bp
index e6f6374..94be786 100644
--- a/services/audiopolicy/managerdefault/Android.bp
+++ b/services/audiopolicy/managerdefault/Android.bp
@@ -41,6 +41,7 @@
// a dependency on it in the device makefile. There will be no build time
// conflict with libaudiopolicyenginedefault.
"audioclient-types-aidl-cpp",
+ "audiopolicy-aidl-cpp",
// Flag support
"android.media.audiopolicy-aconfig-cc",
"com.android.media.audioserver-aconfig-cc",
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index a52ec64..c635feb 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-#include "utils/Errors.h"
#define LOG_TAG "APM_AudioPolicyManager"
// Need to keep the log statements even in production builds
@@ -46,6 +45,7 @@
#include <android_media_audiopolicy.h>
#include <com_android_media_audioserver.h>
#include <cutils/bitops.h>
+#include <error/expected_utils.h>
#include <media/AudioParameter.h>
#include <policy.h>
#include <private/android_filesystem_config.h>
@@ -71,6 +71,8 @@
using android::media::audio::common::AudioMMapPolicyType;
using android::media::audio::common::AudioPortDeviceExt;
using android::media::audio::common::AudioPortExt;
+using android::media::audio::common::AudioConfigBase;
+using binder::Status;
using com::android::media::audioserver::fix_call_audio_patch;
using content::AttributionSourceState;
@@ -1557,7 +1559,8 @@
for (auto &secondaryMix : secondaryMixes) {
sp<SwAudioOutputDescriptor> outputDesc = secondaryMix->getOutput();
if (outputDesc != nullptr &&
- outputDesc->mIoHandle != AUDIO_IO_HANDLE_NONE) {
+ outputDesc->mIoHandle != AUDIO_IO_HANDLE_NONE &&
+ outputDesc->mIoHandle != *output) {
secondaryOutputs->push_back(outputDesc->mIoHandle);
weakSecondaryOutputDescs.push_back(outputDesc);
}
@@ -2925,63 +2928,67 @@
return false;
}
-status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
- audio_io_handle_t *input,
- audio_unique_id_t riid,
- audio_session_t session,
- const AttributionSourceState& attributionSource,
- audio_config_base_t *config,
- audio_input_flags_t flags,
- audio_port_handle_t *selectedDeviceId,
- input_type_t *inputType,
- audio_port_handle_t *portId,
- uint32_t *virtualDeviceId)
+base::expected<media::GetInputForAttrResponse, std::variant<binder::Status, AudioConfigBase>>
+AudioPolicyManager::getInputForAttr(audio_attributes_t attributes,
+ audio_io_handle_t requestedInput,
+ audio_port_handle_t requestedDeviceId,
+ audio_config_base_t config,
+ audio_input_flags_t flags,
+ audio_unique_id_t riid,
+ audio_session_t session,
+ const AttributionSourceState& attributionSource)
{
ALOGV("%s() source %d, sampling rate %d, format %#x, channel mask %#x, session %d, "
"flags %#x attributes=%s requested device ID %d",
- __func__, attr->source, config->sample_rate, config->format, config->channel_mask,
- session, flags, toString(*attr).c_str(), *selectedDeviceId);
+ __func__, attributes.source, config.sample_rate, config.format, config.channel_mask,
+ session, flags, toString(attributes).c_str(), requestedDeviceId);
- status_t status = NO_ERROR;
- audio_attributes_t attributes = *attr;
sp<AudioPolicyMix> policyMix;
sp<DeviceDescriptor> device;
sp<AudioInputDescriptor> inputDesc;
sp<AudioInputDescriptor> previousInputDesc;
sp<RecordClientDescriptor> clientDesc;
- audio_port_handle_t requestedDeviceId = *selectedDeviceId;
- uid_t uid = VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_uid_t(attributionSource.uid));
+ uid_t uid = static_cast<uid_t>(attributionSource.uid);
bool isSoundTrigger;
+ int vdi = 0 /* default device id */;
+ audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
- // The supplied portId must be AUDIO_PORT_HANDLE_NONE
- if (*portId != AUDIO_PORT_HANDLE_NONE) {
- return INVALID_OPERATION;
- }
-
- if (attr->source == AUDIO_SOURCE_DEFAULT) {
+ if (attributes.source == AUDIO_SOURCE_DEFAULT) {
attributes.source = AUDIO_SOURCE_MIC;
}
+ using PermissionReqs = AudioPolicyClientInterface::PermissionReqs;
+ using MixType = AudioPolicyClientInterface::MixType;
+ PermissionReqs permReq {
+ .source = legacy2aidl_audio_source_t_AudioSource(attributes.source).value(),
+ .mixType = MixType::NONE, // can be modified
+ .virtualDeviceId = 0, // can be modified
+ .isHotword = (flags & (AUDIO_INPUT_FLAG_HW_HOTWORD | AUDIO_INPUT_FLAG_HOTWORD_TAP |
+ AUDIO_INPUT_FLAG_HW_LOOKBACK)) != 0,
+ .isCallRedir = (attributes.flags & AUDIO_FLAG_CALL_REDIRECTION) != 0,
+ };
+
// Explicit routing?
sp<DeviceDescriptor> explicitRoutingDevice =
- mAvailableInputDevices.getDeviceFromId(*selectedDeviceId);
+ mAvailableInputDevices.getDeviceFromId(requestedDeviceId);
// special case for mmap capture: if an input IO handle is specified, we reuse this input if
// possible
if ((flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) == AUDIO_INPUT_FLAG_MMAP_NOIRQ &&
- *input != AUDIO_IO_HANDLE_NONE) {
- ssize_t index = mInputs.indexOfKey(*input);
+ requestedInput != AUDIO_IO_HANDLE_NONE) {
+ input = requestedInput;
+ ssize_t index = mInputs.indexOfKey(requestedInput);
if (index < 0) {
- ALOGW("getInputForAttr() unknown MMAP input %d", *input);
- status = BAD_VALUE;
- goto error;
+ return base::unexpected{Status::fromExceptionCode(
+ EX_ILLEGAL_ARGUMENT,
+ String8::format("%s unknown MMAP input %d", __func__, requestedInput))};
}
sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
RecordClientVector clients = inputDesc->getClientsForSession(session);
if (clients.size() == 0) {
- ALOGW("getInputForAttr() unknown session %d on input %d", session, *input);
- status = BAD_VALUE;
- goto error;
+ return base::unexpected{Status::fromExceptionCode(
+ EX_ILLEGAL_ARGUMENT, String8::format("%s unknown session %d on input %d",
+ __func__, session, requestedInput))};
}
// For MMAP mode, the first call to getInputForAttr() is made on behalf of audioflinger.
// The second call is for the first active client and sets the UID. Any further call
@@ -2997,146 +3004,158 @@
continue;
}
if (uid != client->uid() && !client->isSilenced()) {
- ALOGW("getInputForAttr() bad uid %d for client %d uid %d",
- uid, client->portId(), client->uid());
- status = INVALID_OPERATION;
- goto error;
+ return base::unexpected{Status::fromExceptionCode(
+ EX_ILLEGAL_STATE,
+ String8::format("%s bad uid %d for client %d uid %d", __func__, uid,
+ client->portId(), client->uid()))};
}
}
}
- *inputType = API_INPUT_LEGACY;
device = inputDesc->getDevice();
-
- ALOGV("%s reusing MMAP input %d for session %d", __FUNCTION__, *input, session);
- goto exit;
- }
-
- *input = AUDIO_IO_HANDLE_NONE;
- *inputType = API_INPUT_INVALID;
-
- if (attributes.source == AUDIO_SOURCE_REMOTE_SUBMIX &&
- extractAddressFromAudioAttributes(attributes).has_value()) {
- status = mPolicyMixes.getInputMixForAttr(attributes, &policyMix);
- if (status != NO_ERROR) {
- ALOGW("%s could not find input mix for attr %s",
- __func__, toString(attributes).c_str());
- goto error;
- }
- device = mAvailableInputDevices.getDevice(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
- String8(attr->tags + strlen("addr=")),
- AUDIO_FORMAT_DEFAULT);
- if (device == nullptr) {
- ALOGW("%s could not find in Remote Submix device for source %d, tags %s",
- __func__, attributes.source, attributes.tags);
- status = BAD_VALUE;
- goto error;
- }
-
- if (is_mix_loopback_render(policyMix->mRouteFlags)) {
- *inputType = API_INPUT_MIX_PUBLIC_CAPTURE_PLAYBACK;
- } else {
- *inputType = API_INPUT_MIX_EXT_POLICY_REROUTE;
- }
- if (virtualDeviceId) {
- *virtualDeviceId = policyMix->mVirtualDeviceId;
+ ALOGV("%s reusing MMAP input %d for session %d", __FUNCTION__, requestedInput, session);
+ auto permRes = mpClientInterface->checkPermissionForInput(attributionSource, permReq);
+ if (!permRes.has_value()) return base::unexpected {permRes.error()};
+ if (!permRes.value()) {
+ return base::unexpected{Status::fromExceptionCode(
+ EX_SECURITY, String8::format("%s: %s missing perms for source %d mix %d vdi %d"
+ "hotword? %d callredir? %d", __func__, attributionSource.toString().c_str(),
+ static_cast<int>(permReq.source),
+ static_cast<int>(permReq.mixType),
+ permReq.virtualDeviceId,
+ permReq.isHotword,
+ permReq.isCallRedir))};
}
} else {
- if (explicitRoutingDevice != nullptr) {
- device = explicitRoutingDevice;
+ if (attributes.source == AUDIO_SOURCE_REMOTE_SUBMIX &&
+ extractAddressFromAudioAttributes(attributes).has_value()) {
+ status_t status = mPolicyMixes.getInputMixForAttr(attributes, &policyMix);
+ if (status != NO_ERROR) {
+ ALOGW("%s could not find input mix for attr %s",
+ __func__, toString(attributes).c_str());
+ return base::unexpected {aidl_utils::binderStatusFromStatusT(status)};
+ }
+ device = mAvailableInputDevices.getDevice(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
+ String8(attributes.tags + strlen("addr=")),
+ AUDIO_FORMAT_DEFAULT);
+ if (device == nullptr) {
+ return base::unexpected{Status::fromExceptionCode(
+ EX_ILLEGAL_ARGUMENT,
+ String8::format(
+ "%s could not find in Remote Submix device for source %d, tags %s",
+ __func__, attributes.source, attributes.tags))};
+ }
+
+ if (is_mix_loopback_render(policyMix->mRouteFlags)) {
+ permReq.mixType = MixType::PUBLIC_CAPTURE_PLAYBACK;
+ } else {
+ permReq.mixType = MixType::EXT_POLICY_REROUTE;
+ }
+ // TODO is this correct?
+ permReq.virtualDeviceId = policyMix->mVirtualDeviceId;
} else {
- // Prevent from storing invalid requested device id in clients
- requestedDeviceId = AUDIO_PORT_HANDLE_NONE;
- device = mEngine->getInputDeviceForAttributes(attributes, uid, session, &policyMix);
- ALOGV_IF(device != nullptr, "%s found device type is 0x%X",
- __FUNCTION__, device->type());
- }
- if (device == nullptr) {
- ALOGW("getInputForAttr() could not find device for source %d", attributes.source);
- status = BAD_VALUE;
- goto error;
- }
- if (device->type() == AUDIO_DEVICE_IN_ECHO_REFERENCE) {
- *inputType = API_INPUT_MIX_CAPTURE;
- } else 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
- // know about it and is therefore considered "legacy"
- *inputType = API_INPUT_LEGACY;
-
- if (virtualDeviceId) {
- *virtualDeviceId = policyMix->mVirtualDeviceId;
+ if (explicitRoutingDevice != nullptr) {
+ device = explicitRoutingDevice;
+ } else {
+ // Prevent from storing invalid requested device id in clients
+ requestedDeviceId = AUDIO_PORT_HANDLE_NONE;
+ device = mEngine->getInputDeviceForAttributes(attributes, uid, session, &policyMix);
+ ALOGV_IF(device != nullptr, "%s found device type is 0x%X",
+ __FUNCTION__, device->type());
}
- } else if (audio_is_remote_submix_device(device->type())) {
- *inputType = API_INPUT_MIX_CAPTURE;
- } else if (device->type() == AUDIO_DEVICE_IN_TELEPHONY_RX) {
- *inputType = API_INPUT_TELEPHONY_RX;
- } else {
- *inputType = API_INPUT_LEGACY;
+ if (device == nullptr) {
+ return base::unexpected{Status::fromExceptionCode(
+ EX_ILLEGAL_ARGUMENT,
+ String8::format("%s could not find device for source %d", __func__,
+ attributes.source))};
+ }
+ if (device->type() == AUDIO_DEVICE_IN_ECHO_REFERENCE) {
+ permReq.mixType = MixType::CAPTURE;
+ } else 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
+ // know about it and is therefore considered "legacy"
+ permReq.mixType = MixType::NONE;
+ permReq.virtualDeviceId = policyMix->mVirtualDeviceId;
+ } else if (audio_is_remote_submix_device(device->type())) {
+ permReq.mixType = MixType::CAPTURE;
+ } else if (device->type() == AUDIO_DEVICE_IN_TELEPHONY_RX) {
+ permReq.mixType = MixType::TELEPHONY_RX_CAPTURE;
+ } else {
+ permReq.mixType = MixType::NONE;
+ }
}
+ auto permRes = mpClientInterface->checkPermissionForInput(attributionSource, permReq);
+ if (!permRes.has_value()) return base::unexpected {permRes.error()};
+ if (!permRes.value()) {
+ return base::unexpected{Status::fromExceptionCode(
+ EX_SECURITY, String8::format("%s: %s missing perms for source %d mix %d vdi %d"
+ "hotword? %d callredir? %d", __func__, attributionSource.toString().c_str(),
+ static_cast<int>(permReq.source),
+ static_cast<int>(permReq.mixType),
+ permReq.virtualDeviceId,
+ permReq.isHotword,
+ permReq.isCallRedir))};
+ }
+
+ input = getInputForDevice(device, session, attributes, config, flags, policyMix);
+ if (input == AUDIO_IO_HANDLE_NONE) {
+ AudioProfileVector profiles;
+ status_t ret = getProfilesForDevices(
+ DeviceVector(device), profiles, flags, true /*isInput*/);
+ if (ret == NO_ERROR && !profiles.empty()) {
+ const auto channels = profiles[0]->getChannels();
+ if (!channels.empty() && (channels.find(config.channel_mask) == channels.end())) {
+ config.channel_mask = *channels.begin();
+ }
+ const auto sampleRates = profiles[0]->getSampleRates();
+ if (!sampleRates.empty() &&
+ (sampleRates.find(config.sample_rate) == sampleRates.end())) {
+ config.sample_rate = *sampleRates.begin();
+ }
+ config.format = profiles[0]->getFormat();
+ }
+ const auto suggestedConfig = VALUE_OR_FATAL(
+ legacy2aidl_audio_config_base_t_AudioConfigBase(config, true /*isInput*/));
+ return base::unexpected {suggestedConfig};
+ }
}
- *input = getInputForDevice(device, session, attributes, config, flags, policyMix);
- if (*input == AUDIO_IO_HANDLE_NONE) {
- status = INVALID_OPERATION;
- AudioProfileVector profiles;
- status_t ret = getProfilesForDevices(
- DeviceVector(device), profiles, flags, true /*isInput*/);
- if (ret == NO_ERROR && !profiles.empty()) {
- const auto channels = profiles[0]->getChannels();
- if (!channels.empty() && (channels.find(config->channel_mask) == channels.end())) {
- config->channel_mask = *channels.begin();
- }
- const auto sampleRates = profiles[0]->getSampleRates();
- if (!sampleRates.empty() &&
- (sampleRates.find(config->sample_rate) == sampleRates.end())) {
- config->sample_rate = *sampleRates.begin();
- }
- config->format = profiles[0]->getFormat();
- }
- goto error;
- }
-
-
- if (policyMix != nullptr && virtualDeviceId != nullptr) {
- *virtualDeviceId = policyMix->mVirtualDeviceId;
- }
-
-exit:
-
- *selectedDeviceId = mAvailableInputDevices.contains(device) ?
+ auto selectedDeviceId = mAvailableInputDevices.contains(device) ?
device->getId() : AUDIO_PORT_HANDLE_NONE;
isSoundTrigger = attributes.source == AUDIO_SOURCE_HOTWORD &&
mSoundTriggerSessions.indexOfKey(session) >= 0;
- *portId = PolicyAudioPort::getNextUniqueId();
- clientDesc = new RecordClientDescriptor(*portId, riid, uid, session, attributes, *config,
+ const auto allocatedPortId = PolicyAudioPort::getNextUniqueId();
+
+ clientDesc = new RecordClientDescriptor(allocatedPortId, riid, uid, session, attributes, config,
requestedDeviceId, attributes.source, flags,
isSoundTrigger);
- inputDesc = mInputs.valueFor(*input);
+ inputDesc = mInputs.valueFor(input);
// Move (if found) effect for the client session to its input
- mEffects.moveEffectsForIo(session, *input, &mInputs, mpClientInterface);
+ mEffects.moveEffectsForIo(session, input, &mInputs, mpClientInterface);
inputDesc->addClient(clientDesc);
- ALOGV("getInputForAttr() returns input %d type %d selectedDeviceId %d for port ID %d",
- *input, *inputType, *selectedDeviceId, *portId);
+ ALOGV("getInputForAttr() returns input %d selectedDeviceId %d vdi %d for port ID %d",
+ input, selectedDeviceId, permReq.virtualDeviceId, allocatedPortId);
- return NO_ERROR;
-
-error:
- return status;
+ auto ret = media::GetInputForAttrResponse {};
+ ret.input = input;
+ ret.selectedDeviceId = selectedDeviceId;
+ ret.portId = allocatedPortId;
+ ret.virtualDeviceId = permReq.virtualDeviceId;
+ ret.config = legacy2aidl_audio_config_base_t_AudioConfigBase(config, true /*isInput*/).value();
+ return ret;
}
-
-audio_io_handle_t AudioPolicyManager::getInputForDevice(const sp<DeviceDescriptor> &device,
+audio_io_handle_t AudioPolicyManager::getInputForDevice(const sp<DeviceDescriptor>& device,
audio_session_t session,
- const audio_attributes_t &attributes,
- audio_config_base_t *config,
+ const audio_attributes_t& attributes,
+ const audio_config_base_t& config,
audio_input_flags_t flags,
- const sp<AudioPolicyMix> &policyMix)
-{
+ const sp<AudioPolicyMix>& policyMix) {
audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
audio_source_t halInputSource = attributes.source;
bool isSoundTrigger = false;
@@ -3152,7 +3171,7 @@
halInputSource = AUDIO_SOURCE_VOICE_RECOGNITION;
}
} else if (attributes.source == AUDIO_SOURCE_VOICE_COMMUNICATION &&
- audio_is_linear_pcm(config->format)) {
+ audio_is_linear_pcm(config.format)) {
flags = (audio_input_flags_t)(flags | AUDIO_INPUT_FLAG_VOIP_TX);
}
@@ -3161,10 +3180,10 @@
}
// sampling rate and flags may be updated by getInputProfile
- uint32_t profileSamplingRate = (config->sample_rate == 0) ?
- SAMPLE_RATE_HZ_DEFAULT : config->sample_rate;
- audio_format_t profileFormat = config->format;
- audio_channel_mask_t profileChannelMask = config->channel_mask;
+ uint32_t profileSamplingRate = (config.sample_rate == 0) ?
+ SAMPLE_RATE_HZ_DEFAULT : config.sample_rate;
+ audio_format_t profileFormat = config.format;
+ audio_channel_mask_t profileChannelMask = config.channel_mask;
audio_input_flags_t profileFlags = flags;
// find a compatible input profile (not necessarily identical in parameters)
sp<IOProfile> profile = getInputProfile(
@@ -3174,7 +3193,7 @@
}
// Pick input sampling rate if not specified by client
- uint32_t samplingRate = config->sample_rate;
+ uint32_t samplingRate = config.sample_rate;
if (samplingRate == 0) {
samplingRate = profileSamplingRate;
}
@@ -3582,23 +3601,30 @@
return BAD_VALUE;
}
- if (mAbsoluteVolumeDrivingStreams[deviceType] != attributesToDriveAbs) {
+ const auto attrIt = mAbsoluteVolumeDrivingStreams.find(deviceType);
+ if (attrIt == mAbsoluteVolumeDrivingStreams.end() ||
+ (attrIt->second.usage != attributesToDriveAbs.usage ||
+ attrIt->second.content_type != attributesToDriveAbs.content_type ||
+ attrIt->second.flags != attributesToDriveAbs.flags)) {
mAbsoluteVolumeDrivingStreams[deviceType] = attributesToDriveAbs;
changed = true;
}
} else {
- if (mAbsoluteVolumeDrivingStreams.find(deviceType) != mAbsoluteVolumeDrivingStreams.end()) {
- mAbsoluteVolumeDrivingStreams.erase(deviceType);
+ if (mAbsoluteVolumeDrivingStreams.erase(deviceType) != 0) {
changed = true;
}
}
- // if something changed, apply the stream volumes regarding the new absolute mode to all the
- // outputs without any delay
+ const DeviceVector devices = mEngine->getOutputDevicesForAttributes(
+ attributesToDriveAbs, nullptr /* preferredDevice */, true /* fromCache */);
+ changed &= devices.types().contains(deviceType);
+ // if something changed on the output device for the changed attributes, apply the stream
+ // volumes regarding the new absolute mode to all the outputs without any delay
if (changed) {
for (size_t i = 0; i < mOutputs.size(); i++) {
sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
- ALOGV("%s: apply stream volumes for portId %d", __func__, desc->getId());
+ ALOGI("%s: apply stream volumes for portId %d and device type %d", __func__,
+ desc->getId(), deviceType);
applyStreamVolumes(desc, {deviceType});
}
}
@@ -3791,19 +3817,21 @@
}
}
- // update voice volume if the an active call route exists
- if (mCallRxSourceClient != nullptr && mCallRxSourceClient->isConnected()
- && (curSrcDevices.find(
- Volume::getDeviceForVolume({mCallRxSourceClient->sinkDevice()->type()}))
- != curSrcDevices.end())) {
- bool isVoiceVolSrc;
- bool isBtScoVolSrc;
- if (isVolumeConsistentForCalls(vs, {mCallRxSourceClient->sinkDevice()->type()},
- isVoiceVolSrc, isBtScoVolSrc, __func__)
- && (isVoiceVolSrc || isBtScoVolSrc)) {
- bool voiceVolumeManagedByHost = !isBtScoVolSrc &&
- !audio_is_ble_out_device(mCallRxSourceClient->sinkDevice()->type());
- setVoiceVolume(index, curves, voiceVolumeManagedByHost, 0);
+ // update voice volume if the an active call route exists and target device is same as current
+ if (mCallRxSourceClient != nullptr && mCallRxSourceClient->isConnected()) {
+ audio_devices_t rxSinkDevice = mCallRxSourceClient->sinkDevice()->type();
+ audio_devices_t curVoiceDevice = Volume::getDeviceForVolume({rxSinkDevice});
+ if (curVoiceDevice == device
+ && curSrcDevices.find(curVoiceDevice) != curSrcDevices.end()) {
+ bool isVoiceVolSrc;
+ bool isBtScoVolSrc;
+ if (isVolumeConsistentForCalls(vs, {rxSinkDevice},
+ isVoiceVolSrc, isBtScoVolSrc, __func__)
+ && (isVoiceVolSrc || isBtScoVolSrc)) {
+ bool voiceVolumeManagedByHost = !isBtScoVolSrc &&
+ !audio_is_ble_out_device(rxSinkDevice);
+ setVoiceVolume(index, curves, voiceVolumeManagedByHost, 0);
+ }
}
}
@@ -7640,7 +7668,8 @@
for (auto &secondaryMix : secondaryMixes) {
sp<SwAudioOutputDescriptor> outputDesc = secondaryMix->getOutput();
if (outputDesc != nullptr &&
- outputDesc->mIoHandle != AUDIO_IO_HANDLE_NONE) {
+ outputDesc->mIoHandle != AUDIO_IO_HANDLE_NONE &&
+ outputDesc != outputDescriptor) {
secondaryDescs.push_back(outputDesc);
}
}
@@ -7839,7 +7868,8 @@
}
// Honor explicit routing requests only if no client using default routing is active on this
- // input: a specific app can not force routing for other apps by setting a preferred device.
+ // input or if all active clients are from the same app: a specific app can not force routing
+ // for other apps by setting a preferred device.
bool active;
device = findPreferredDevice(inputDesc, AUDIO_SOURCE_DEFAULT, active, mAvailableInputDevices);
if (device != nullptr) {
@@ -8649,7 +8679,6 @@
const bool isHAUsed = isHearingAidUsedForComm();
if (com_android_media_audio_replace_stream_bt_sco()) {
- ALOGV("%s stream bt sco is replaced, no volume consistency check for calls", __func__);
isBtScoVolSrc = (volumeSource != VOLUME_SOURCE_NONE) && (callVolSrc == volumeSource) &&
(isScoRequested || isHAUsed);
return true;
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index e0cafd4..44863ee 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -134,17 +134,17 @@
virtual status_t startOutput(audio_port_handle_t portId);
virtual status_t stopOutput(audio_port_handle_t portId);
virtual bool releaseOutput(audio_port_handle_t portId);
- virtual status_t getInputForAttr(const audio_attributes_t *attr,
- audio_io_handle_t *input,
+
+ base::expected<media::GetInputForAttrResponse, std::variant<binder::Status,
+ media::audio::common::AudioConfigBase>>
+ getInputForAttr(audio_attributes_t attributes,
+ audio_io_handle_t requestedInput,
+ audio_port_handle_t requestedDeviceId,
+ audio_config_base_t config,
+ audio_input_flags_t flags,
audio_unique_id_t riid,
audio_session_t session,
- const AttributionSourceState& attributionSource,
- audio_config_base_t *config,
- audio_input_flags_t flags,
- audio_port_handle_t *selectedDeviceId,
- input_type_t *inputType,
- audio_port_handle_t *portId,
- uint32_t *virtualDeviceId);
+ const AttributionSourceState& attributionSource) override;
// indicates to the audio policy manager that the input starts being used.
virtual status_t startInput(audio_port_handle_t portId);
@@ -1226,7 +1226,7 @@
audio_io_handle_t getInputForDevice(const sp<DeviceDescriptor> &device,
audio_session_t session,
const audio_attributes_t &attributes,
- audio_config_base_t *config,
+ const audio_config_base_t &config,
audio_input_flags_t flags,
const sp<AudioPolicyMix> &policyMix);
diff --git a/services/audiopolicy/service/Android.bp b/services/audiopolicy/service/Android.bp
index 619c924..f415a41 100644
--- a/services/audiopolicy/service/Android.bp
+++ b/services/audiopolicy/service/Android.bp
@@ -11,6 +11,10 @@
cc_defaults {
name: "libaudiopolicyservice_dependencies",
+ defaults: [
+ "latest_android_media_audio_common_types_cpp_shared",
+ ],
+
include_dirs: [
"frameworks/av/services/audiopolicy", // include path outside of libaudiopolicyservice
],
@@ -21,7 +25,6 @@
"audio-permission-aidl-cpp",
"audioclient-types-aidl-cpp",
"audioflinger-aidl-cpp",
- "audiopermissioncontroller",
"audiopolicy-aidl-cpp",
"audiopolicy-types-aidl-cpp",
"capture_state_listener-aidl-cpp",
@@ -33,6 +36,7 @@
"libaudioclient_aidl_conversion",
"libaudiofoundation",
"libaudiohal",
+ "libaudiopermission",
"libaudiopolicy",
"libaudiopolicycomponents",
"libaudiopolicymanagerdefault",
@@ -64,7 +68,6 @@
name: "libaudiopolicyservice",
defaults: [
- "latest_android_media_audio_common_types_cpp_shared",
"libaudiopolicyservice_dependencies",
],
@@ -115,6 +118,6 @@
name: "audiopolicyservicelocal_headers",
host_supported: true,
export_include_dirs: ["include"],
- header_libs: ["audiopermissioncontroller_headers"],
- export_header_lib_headers: ["audiopermissioncontroller_headers"],
+ header_libs: ["libaudiopermission_headers"],
+ export_header_lib_headers: ["libaudiopermission_headers"],
}
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 20bc788..12320b7 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -87,8 +87,6 @@
using media::audio::common::AudioFormatDescription;
using media::audio::common::AudioMode;
using media::audio::common::AudioOffloadInfo;
-using media::audio::common::AudioPolicyForceUse;
-using media::audio::common::AudioPolicyForcedConfig;
using media::audio::common::AudioSource;
using media::audio::common::AudioStreamType;
using media::audio::common::AudioUsage;
@@ -298,8 +296,8 @@
return Status::ok();
}
-Status AudioPolicyService::setForceUse(AudioPolicyForceUse usageAidl,
- AudioPolicyForcedConfig configAidl)
+Status AudioPolicyService::setForceUse(media::AudioPolicyForceUse usageAidl,
+ media::AudioPolicyForcedConfig configAidl)
{
audio_policy_force_use_t usage = VALUE_OR_RETURN_BINDER_STATUS(
aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t(usageAidl));
@@ -330,8 +328,8 @@
return Status::ok();
}
-Status AudioPolicyService::getForceUse(AudioPolicyForceUse usageAidl,
- AudioPolicyForcedConfig* _aidl_return) {
+Status AudioPolicyService::getForceUse(media::AudioPolicyForceUse usageAidl,
+ media::AudioPolicyForcedConfig* _aidl_return) {
audio_policy_force_use_t usage = VALUE_OR_RETURN_BINDER_STATUS(
aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t(usageAidl));
@@ -680,13 +678,14 @@
}
}
-error::BinderResult<bool> AudioPolicyService::evaluatePermsForSource(
- const AttributionSourceState& attrSource, AudioSource source, bool isHotword) {
+error::BinderResult<bool> AudioPolicyService::AudioPolicyClient::checkPermissionForInput(
+ const AttributionSourceState& attrSource, const PermissionReqs& req) {
+
error::BinderResult<bool> permRes = true;
const auto check_perm = [&](PermissionEnum perm, uid_t uid) {
- return getPermissionProvider().checkPermission(perm, uid);
+ return mAudioPolicyService->getPermissionProvider().checkPermission(perm, uid);
};
- switch (source) {
+ switch (req.source) {
case AudioSource::VOICE_UPLINK:
case AudioSource::VOICE_DOWNLINK:
case AudioSource::VOICE_CALL:
@@ -721,14 +720,13 @@
case AudioSource::VOICE_PERFORMANCE:
// No additional check intended
case AudioSource::REMOTE_SUBMIX:
- // special-case checked based on device (evaluatePermsForDevice)
+ // special-case checked based on mix type below
break;
}
- bool isAllowed = VALUE_OR_RETURN(permRes);
-
- if (!isAllowed) {
- if (isLegacyOutputSource(source)) {
+ if (!permRes.has_value()) return permRes;
+ if (!permRes.value()) {
+ if (isLegacyOutputSource(req.source)) {
permRes = audioserver_permissions() ? check_perm(CAPTURE_AUDIO_OUTPUT, attrSource.uid)
: captureAudioOutputAllowed(attrSource);
PROPAGATE_FALSEY(permRes);
@@ -737,70 +735,61 @@
}
}
- if (isHotword) {
+ if (req.isHotword) {
permRes = audioserver_permissions() ? check_perm(CAPTURE_AUDIO_HOTWORD, attrSource.uid)
: captureHotwordAllowed(attrSource);
PROPAGATE_FALSEY(permRes);
}
- // All sources which aren't output capture require RECORD as well,
- // as well as vdi policy mix
- const auto legacySource = aidl2legacy_AudioSource_audio_source_t(source).value();
- if (isRecordOpRequired(legacySource)) {
- permRes = audioserver_permissions() ? check_perm(RECORD_AUDIO, attrSource.uid)
- : recordingAllowed(attrSource, legacySource);
- PROPAGATE_FALSEY(permRes);
- }
- return true;
-}
-
-error::BinderResult<bool> AudioPolicyService::evaluatePermsForDevice(
- const AttributionSourceState& attrSource, AudioSource source,
- AudioPolicyInterface::input_type_t inputType, uint32_t vdi, bool isCallRedir) {
- // enforce permission (if any) required for each type of input
- error::BinderResult<bool> permRes = true;
- const auto check_perm = [&](PermissionEnum perm, uid_t uid) {
- return getPermissionProvider().checkPermission(perm, uid);
- };
+ // TODO evaluate whether we should be checking call redirection like this
bool isAllowedDueToCallPerm = false;
- if (isCallRedir) {
+ if (req.isCallRedir) {
const auto checkCall = audioserver_permissions()
- ? check_perm(CALL_AUDIO_INTERCEPTION, attrSource.uid)
- : callAudioInterceptionAllowed(attrSource);
+ ? check_perm(CALL_AUDIO_INTERCEPTION, attrSource.uid)
+ : callAudioInterceptionAllowed(attrSource);
isAllowedDueToCallPerm = VALUE_OR_RETURN(checkCall);
}
- switch (inputType) {
- case AudioPolicyInterface::API_INPUT_MIX_PUBLIC_CAPTURE_PLAYBACK:
+
+ switch (req.mixType) {
+ case MixType::NONE:
+ break;
+ case MixType::PUBLIC_CAPTURE_PLAYBACK:
// this use case has been validated in audio service with a MediaProjection token,
// and doesn't rely on regular permissions
- case AudioPolicyInterface::API_INPUT_LEGACY:
+ // TODO (b/378778313)
break;
- case AudioPolicyInterface::API_INPUT_TELEPHONY_RX:
+ case MixType::TELEPHONY_RX_CAPTURE:
if (isAllowedDueToCallPerm) break;
// FIXME: use the same permission as for remote submix for now.
FALLTHROUGH_INTENDED;
- case AudioPolicyInterface::API_INPUT_MIX_CAPTURE:
+ case MixType::CAPTURE:
permRes = audioserver_permissions() ? check_perm(CAPTURE_AUDIO_OUTPUT, attrSource.uid)
: captureAudioOutputAllowed(attrSource);
break;
- case AudioPolicyInterface::API_INPUT_MIX_EXT_POLICY_REROUTE: {
+ case MixType::EXT_POLICY_REROUTE:
// TODO intended?
if (isAllowedDueToCallPerm) break;
permRes = audioserver_permissions() ? check_perm(MODIFY_AUDIO_ROUTING, attrSource.uid)
: modifyAudioRoutingAllowed(attrSource);
break;
- }
- case AudioPolicyInterface::API_INPUT_INVALID:
- default:
- LOG_ALWAYS_FATAL("%s encountered an invalid input type %d", __func__, (int)inputType);
}
PROPAGATE_FALSEY(permRes);
- if (audiopolicy_flags::record_audio_device_aware_permission()) {
- // enforce device-aware RECORD_AUDIO permission
- const auto legacySource = aidl2legacy_AudioSource_audio_source_t(source).value();
- return vdi == kDefaultVirtualDeviceId || recordingAllowed(attrSource, vdi, legacySource);
+ // All sources which aren't output capture
+ // AND capture from vdi policy mix (the injected audio is mic data from another device)
+ // REQUIRE RECORD perms
+ const auto legacySource = aidl2legacy_AudioSource_audio_source_t(req.source).value();
+ if (req.virtualDeviceId != kDefaultVirtualDeviceId) {
+ // TODO assert that this is always a recordOpSource
+ // TODO upcall solution
+ return recordingAllowed(attrSource, req.virtualDeviceId, legacySource);
+ }
+
+ if (isRecordOpRequired(legacySource)) {
+ permRes = audioserver_permissions() ? check_perm(RECORD_AUDIO, attrSource.uid)
+ : recordingAllowed(attrSource, legacySource);
+ PROPAGATE_FALSEY(permRes);
}
return true;
}
@@ -815,23 +804,21 @@
int32_t selectedDeviceIdAidl,
media::GetInputForAttrResponse* _aidl_return) {
auto inputSource = attrAidl.source;
- audio_attributes_t attr = VALUE_OR_RETURN_BINDER_STATUS(
+ const audio_attributes_t attr = VALUE_OR_RETURN_BINDER_STATUS(
aidl2legacy_AudioAttributes_audio_attributes_t(attrAidl));
- audio_io_handle_t input = VALUE_OR_RETURN_BINDER_STATUS(
+ const audio_io_handle_t requestedInput = VALUE_OR_RETURN_BINDER_STATUS(
aidl2legacy_int32_t_audio_io_handle_t(inputAidl));
- audio_unique_id_t riid = VALUE_OR_RETURN_BINDER_STATUS(
+ const audio_unique_id_t riid = VALUE_OR_RETURN_BINDER_STATUS(
aidl2legacy_int32_t_audio_unique_id_t(riidAidl));
- audio_session_t session = VALUE_OR_RETURN_BINDER_STATUS(
+ const audio_session_t session = VALUE_OR_RETURN_BINDER_STATUS(
aidl2legacy_int32_t_audio_session_t(sessionAidl));
- audio_config_base_t config = VALUE_OR_RETURN_BINDER_STATUS(
+ const audio_config_base_t config = VALUE_OR_RETURN_BINDER_STATUS(
aidl2legacy_AudioConfigBase_audio_config_base_t(configAidl, true /*isInput*/));
- audio_input_flags_t flags = VALUE_OR_RETURN_BINDER_STATUS(
+ const audio_input_flags_t flags = VALUE_OR_RETURN_BINDER_STATUS(
aidl2legacy_int32_t_audio_input_flags_t_mask(flagsAidl));
- audio_port_handle_t selectedDeviceId = VALUE_OR_RETURN_BINDER_STATUS(
+ const audio_port_handle_t requestedDeviceId = VALUE_OR_RETURN_BINDER_STATUS(
aidl2legacy_int32_t_audio_port_handle_t(selectedDeviceIdAidl));
- audio_port_handle_t portId;
-
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
@@ -849,19 +836,14 @@
inputSource = AudioSource::MIC;
}
- const bool isHotword = (flags & (AUDIO_INPUT_FLAG_HW_HOTWORD | AUDIO_INPUT_FLAG_HOTWORD_TAP |
- AUDIO_INPUT_FLAG_HW_LOOKBACK)) != 0;
-
const bool isCallRedir = (attr.flags & AUDIO_FLAG_CALL_REDIRECTION) != 0;
- const bool canCaptureOutput = audioserver_permissions()
- ? CHECK_PERM(CAPTURE_AUDIO_OUTPUT, attributionSource.uid)
- : captureAudioOutputAllowed(attributionSource);
-
//TODO(b/374751406): remove forcing canBypassConcurrentPolicy to canCaptureOutput
// once all system apps using CAPTURE_AUDIO_OUTPUT to capture during calls
// are updated to use the new CONCURRENT_AUDIO_RECORD_BYPASS permission.
- bool canBypassConcurrentPolicy = canCaptureOutput;
+ bool canBypassConcurrentPolicy = audioserver_permissions()
+ ? CHECK_PERM(CAPTURE_AUDIO_OUTPUT, attributionSource.uid)
+ : captureAudioOutputAllowed(attributionSource);
if (concurrent_audio_record_bypass_permission()) {
canBypassConcurrentPolicy = audioserver_permissions() ?
CHECK_PERM(BYPASS_CONCURRENT_RECORD_AUDIO_RESTRICTION,
@@ -869,89 +851,44 @@
: bypassConcurrentPolicyAllowed(attributionSource);
}
- const bool hasPerm = VALUE_OR_RETURN_STATUS(evaluatePermsForSource(
- attributionSource,
- inputSource,
- isHotword));
-
- if (!hasPerm) {
- return Status::fromExceptionCode(
- EX_SECURITY, String8::format("%s: %s missing perms for source %s", __func__,
- attributionSource.toString().c_str(),
- toString(inputSource).c_str()));
- }
-
- uint32_t virtualDeviceId = kDefaultVirtualDeviceId;
-
- sp<AudioPolicyEffects>audioPolicyEffects;
+ sp<AudioPolicyEffects> audioPolicyEffects;
+ base::expected<media::GetInputForAttrResponse, std::variant<binder::Status, AudioConfigBase>>
+ res;
{
- status_t status;
- AudioPolicyInterface::input_type_t inputType;
-
audio_utils::lock_guard _l(mMutex);
- {
- AutoCallerClear acc;
- // the audio_in_acoustics_t parameter is ignored by get_input()
- status = mAudioPolicyManager->getInputForAttr(&attr, &input, riid, session,
- attributionSource, &config,
- flags, &selectedDeviceId,
- &inputType, &portId,
- &virtualDeviceId);
-
- }
- audioPolicyEffects = mAudioPolicyEffects;
-
- if (status == NO_ERROR) {
- const auto permResult = evaluatePermsForDevice(attributionSource,
- inputSource, inputType, virtualDeviceId,
- isCallRedir);
-
- if (!permResult.has_value()) {
- AutoCallerClear acc;
- mAudioPolicyManager->releaseInput(portId);
- return permResult.error();
- } else if (!permResult.value()) {
- AutoCallerClear acc;
- mAudioPolicyManager->releaseInput(portId);
- return Status::fromExceptionCode(
- EX_SECURITY,
- String8::format(
- "%s: %s missing perms for input type %d, inputSource %d, vdi %d",
- __func__, attributionSource.toString().c_str(), inputType,
- inputSource, virtualDeviceId));
+ AutoCallerClear acc;
+ // the audio_in_acoustics_t parameter is ignored by get_input()
+ res = mAudioPolicyManager->getInputForAttr(attr, requestedInput, requestedDeviceId,
+ config, flags, riid, session,
+ attributionSource);
+ if (!res.has_value()) {
+ if (res.error().index() == 1) {
+ _aidl_return->config = std::get<1>(res.error());
+ return Status::fromExceptionCode(EX_ILLEGAL_STATE);
+ } else {
+ return std::get<0>(res.error());
}
}
- if (status != NO_ERROR) {
- _aidl_return->config = VALUE_OR_RETURN_BINDER_STATUS(
- legacy2aidl_audio_config_base_t_AudioConfigBase(config, true /*isInput*/));
- return binderStatusFromStatusT(status);
- }
+ audioPolicyEffects = mAudioPolicyEffects;
- DeviceIdVector selectedDeviceIds = { selectedDeviceId };
- sp<AudioRecordClient> client = new AudioRecordClient(attr, input, session, portId,
- selectedDeviceIds, attributionSource,
- virtualDeviceId,
- canBypassConcurrentPolicy,
- mOutputCommandThread);
- mAudioRecordClients.add(portId, client);
+ sp<AudioRecordClient> client = new AudioRecordClient(
+ attr, res->input, session, res->portId, {res->selectedDeviceId}, attributionSource,
+ res->virtualDeviceId, canBypassConcurrentPolicy, mOutputCommandThread);
+ mAudioRecordClients.add(res->portId, client);
}
- if (audioPolicyEffects != 0) {
+ if (audioPolicyEffects != nullptr) {
// create audio pre processors according to input source
- status_t status = audioPolicyEffects->addInputEffects(input,
+ status_t status = audioPolicyEffects->addInputEffects(res->input,
aidl2legacy_AudioSource_audio_source_t(inputSource).value(), session);
if (status != NO_ERROR && status != ALREADY_EXISTS) {
- ALOGW("Failed to add effects on input %d", input);
+ ALOGW("Failed to add effects on input %d", res->input);
}
}
- _aidl_return->input = VALUE_OR_RETURN_BINDER_STATUS(
- legacy2aidl_audio_io_handle_t_int32_t(input));
- _aidl_return->selectedDeviceId = VALUE_OR_RETURN_BINDER_STATUS(
- legacy2aidl_audio_port_handle_t_int32_t(selectedDeviceId));
- _aidl_return->portId = VALUE_OR_RETURN_BINDER_STATUS(
- legacy2aidl_audio_port_handle_t_int32_t(portId));
+ *_aidl_return = res.value();
+
return Status::ok();
}
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index 5fe200c..acd9fe9 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -108,10 +108,10 @@
const std::string& deviceName,
const AudioFormatDescription& encodedFormat) override;
binder::Status setPhoneState(AudioMode state, int32_t uid) override;
- binder::Status setForceUse(android::media::audio::common::AudioPolicyForceUse usage,
- android::media::audio::common::AudioPolicyForcedConfig config) override;
- binder::Status getForceUse(android::media::audio::common::AudioPolicyForceUse usage,
- android::media::audio::common::AudioPolicyForcedConfig* _aidl_return) override;
+ binder::Status setForceUse(media::AudioPolicyForceUse usage,
+ media::AudioPolicyForcedConfig config) override;
+ binder::Status getForceUse(media::AudioPolicyForceUse usage,
+ media::AudioPolicyForcedConfig* _aidl_return) override;
binder::Status getOutput(AudioStreamType stream, int32_t* _aidl_return) override;
binder::Status getOutputForAttr(const media::audio::common::AudioAttributes& attr,
int32_t session,
@@ -504,14 +504,6 @@
const audio_output_flags_t flags);
status_t unregisterOutput(audio_io_handle_t output);
- error::BinderResult<bool> evaluatePermsForSource(const AttributionSourceState& attrSource,
- AudioSource source, bool isHotword);
-
- error::BinderResult<bool> evaluatePermsForDevice(const AttributionSourceState& attrSource,
- AudioSource source,
- AudioPolicyInterface::input_type_t inputType,
- uint32_t vdi, bool isCallRedir);
-
// If recording we need to make sure the UID is allowed to do that. If the UID is idle
// then it cannot record and gets buffers with zeros - silence. As soon as the UID
// transitions to an active state we will start reporting buffers with data. This approach
@@ -968,6 +960,9 @@
media::audio::common::AudioMMapPolicyType policyType,
std::vector<media::audio::common::AudioMMapPolicyInfo> *policyInfos) override;
+ error::BinderResult<bool> checkPermissionForInput(const AttributionSourceState& attr,
+ const PermissionReqs& req) override;
+
private:
AudioPolicyService *mAudioPolicyService;
};
diff --git a/services/audiopolicy/service/AudioRecordClient.cpp b/services/audiopolicy/service/AudioRecordClient.cpp
index fd344d9..79a7458 100644
--- a/services/audiopolicy/service/AudioRecordClient.cpp
+++ b/services/audiopolicy/service/AudioRecordClient.cpp
@@ -21,6 +21,7 @@
#include "binder/AppOpsManager.h"
#include "mediautils/ServiceUtilities.h"
#include <android_media_audiopolicy.h>
+#include <media/AttrSourceIter.h>
#include <algorithm>
@@ -58,39 +59,6 @@
bool doesPackageTargetAtLeastU(std::string_view packageName) {
return getTargetSdkForPackageName(packageName) >= __ANDROID_API_U__;
}
-
-class AttrSourceItr {
- public:
- using iterator_category = std::forward_iterator_tag;
- using difference_type = std::ptrdiff_t;
- using value_type = AttributionSourceState;
- using pointer = const value_type*;
- using reference = const value_type&;
-
- AttrSourceItr() : mAttr(nullptr) {}
-
- AttrSourceItr(const AttributionSourceState& attr) : mAttr(&attr) {}
-
- reference operator*() const { return *mAttr; }
- pointer operator->() const { return mAttr; }
-
- AttrSourceItr& operator++() {
- mAttr = !mAttr->next.empty() ? mAttr->next.data() : nullptr;
- return *this;
- }
-
- AttrSourceItr operator++(int) {
- AttrSourceItr tmp = *this;
- ++(*this);
- return tmp;
- }
-
- friend bool operator==(const AttrSourceItr& a, const AttrSourceItr& b) = default;
-
- static AttrSourceItr end() { return AttrSourceItr{}; }
-private:
- const AttributionSourceState * mAttr;
-};
} // anonymous
// static
@@ -124,17 +92,32 @@
commandThread);
}
+// The vdi is carried in the attribution source for appops perm checks.
+// Overwrite the entire chain with the vdi associated with the mix this client is attached to
+// This ensures the checkOps triggered by the listener are correct.
+// Note: we still only register for events by package name, so we assume that we get events
+// independent of vdi.
+static AttributionSourceState& overwriteVdi(AttributionSourceState& chain, int vdi) {
+ using permission::AttrSourceIter::begin;
+ using permission::AttrSourceIter::end;
+ if (vdi != 0 /* default vdi */) {
+ std::for_each(begin(chain), end(), [vdi](auto& attr) { attr.deviceId = vdi; });
+ }
+ return chain;
+}
+
OpRecordAudioMonitor::OpRecordAudioMonitor(
- const AttributionSourceState &attributionSource,
+ AttributionSourceState attributionSource,
const uint32_t virtualDeviceId, const audio_attributes_t &attr,
int32_t appOp,
bool shouldMonitorRecord,
wp<AudioPolicyService::AudioCommandThread> commandThread) :
- mHasOp(true), mAttributionSource(attributionSource),
- mVirtualDeviceId(virtualDeviceId), mAttr(attr), mAppOp(appOp),
+ mHasOp(true),
+ mAttributionSource(overwriteVdi(attributionSource, virtualDeviceId)),
+ mVirtualDeviceId(virtualDeviceId), mAttr(attr),
+ mAppOp(appOp),
mShouldMonitorRecord(shouldMonitorRecord),
- mCommandThread(commandThread) {
-}
+ mCommandThread(commandThread) {}
OpRecordAudioMonitor::~OpRecordAudioMonitor()
{
@@ -146,6 +129,9 @@
void OpRecordAudioMonitor::onFirstRef()
{
+ using permission::AttrSourceIter::cbegin;
+ using permission::AttrSourceIter::cend;
+
checkOp();
mOpCallback = new RecordAudioOpCallback(this);
ALOGV("start watching op %d for %s", mAppOp, mAttributionSource.toString().c_str());
@@ -155,7 +141,7 @@
: 0;
const auto reg = [&](int32_t op) {
- std::for_each(AttrSourceItr{mAttributionSource}, AttrSourceItr::end(),
+ std::for_each(cbegin(mAttributionSource), cend(),
[&](const auto& attr) {
mAppOpsManager.startWatchingMode(
op,
@@ -181,9 +167,11 @@
// - not called from constructor,
// - not called from RecordAudioOpCallback because the callback is not installed in this case
void OpRecordAudioMonitor::checkOp(bool updateUidStates) {
+ using permission::AttrSourceIter::cbegin;
+ using permission::AttrSourceIter::cend;
+
const auto check = [&](int32_t op) -> bool {
- return std::all_of(
- AttrSourceItr{mAttributionSource}, AttrSourceItr::end(), [&](const auto& x) {
+ return std::all_of(cbegin(mAttributionSource), cend(), [&](const auto& x) {
return mAppOpsManager.checkOp(op, x.uid,
VALUE_OR_FATAL(aidl2legacy_string_view_String16(
x.packageName.value_or("")))) ==
diff --git a/services/audiopolicy/service/AudioRecordClient.h b/services/audiopolicy/service/AudioRecordClient.h
index f45b4de..6037a8d 100644
--- a/services/audiopolicy/service/AudioRecordClient.h
+++ b/services/audiopolicy/service/AudioRecordClient.h
@@ -43,7 +43,7 @@
wp<AudioPolicyService::AudioCommandThread> commandThread);
private:
- OpRecordAudioMonitor(const AttributionSourceState &attributionSource,
+ OpRecordAudioMonitor(AttributionSourceState attributionSource,
uint32_t virtualDeviceId,
const audio_attributes_t &attr,
int32_t appOp,
diff --git a/services/audiopolicy/service/Spatializer.cpp b/services/audiopolicy/service/Spatializer.cpp
index c7740ad..d177b92 100644
--- a/services/audiopolicy/service/Spatializer.cpp
+++ b/services/audiopolicy/service/Spatializer.cpp
@@ -413,6 +413,29 @@
return BAD_VALUE;
}
+ std::vector<audio_channel_mask_t> spatializedChannelMasks;
+ status = getHalParameter<true>(effect, SPATIALIZER_PARAM_SPATIALIZED_CHANNEL_MASKS,
+ &spatializedChannelMasks);
+ if (status != NO_ERROR) {
+ ALOGW("%s: cannot get SPATIALIZER_PARAM_SPATIALIZED_CHANNEL_MASKS", __func__);
+ return status;
+ }
+ if (spatializedChannelMasks.empty()) {
+ ALOGW("%s: SPATIALIZER_PARAM_SPATIALIZED_CHANNEL_MASKS reports empty", __func__);
+ return BAD_VALUE;
+ }
+ for (const audio_channel_mask_t spatializedMask : spatializedChannelMasks) {
+ // spatialized masks must be contained in the supported input masks
+ if (std::find(mChannelMasks.begin(), mChannelMasks.end(), spatializedMask)
+ != mChannelMasks.end()) {
+ mSpatializedChannelMasks.emplace_back(spatializedMask);
+ } else {
+ ALOGE("%s: spatialized mask %#x not in list reported by PARAM_SUPPORTED_CHANNEL_MASKS",
+ __func__, spatializedMask);
+ return BAD_VALUE;
+ }
+ }
+
if (com::android::media::audio::dsa_over_bt_le_audio()
&& mSupportsHeadTracking) {
mHeadtrackingConnectionMode = HeadTracking::ConnectionMode::FRAMEWORK_PROCESSED;
@@ -474,6 +497,17 @@
return config;
}
+Status Spatializer::getSpatializedChannelMasks(std::vector<int>* masks) {
+ audio_utils::lock_guard lock(mMutex);
+ ALOGV("%s", __func__);
+ if (masks == nullptr) {
+ return binderStatusFromStatusT(BAD_VALUE);
+ }
+ masks->insert(masks->end(), mSpatializedChannelMasks.begin(),
+ mSpatializedChannelMasks.end());
+ return Status::ok();
+ }
+
status_t Spatializer::registerCallback(
const sp<media::INativeSpatializerCallback>& callback) {
audio_utils::lock_guard lock(mMutex);
@@ -1254,6 +1288,10 @@
for (auto& mask : mChannelMasks) {
base::StringAppendF(&ss, "%s", audio_channel_out_mask_to_string(mask));
}
+ base::StringAppendF(&ss, "%smSpatializedChannelMasks: ", prefixSpace.c_str());
+ for (auto& mask : mSpatializedChannelMasks) {
+ base::StringAppendF(&ss, "%s", audio_channel_out_mask_to_string(mask));
+ }
base::StringAppendF(&ss, "\n%smSupportsHeadTracking: %s\n", prefixSpace.c_str(),
mSupportsHeadTracking ? "true" : "false");
// 2. Settings (Output, tracks)
diff --git a/services/audiopolicy/service/Spatializer.h b/services/audiopolicy/service/Spatializer.h
index 5ea3258..6141165 100644
--- a/services/audiopolicy/service/Spatializer.h
+++ b/services/audiopolicy/service/Spatializer.h
@@ -133,6 +133,7 @@
binder::Status setParameter(int key, const std::vector<unsigned char>& value) override;
binder::Status getParameter(int key, std::vector<unsigned char> *value) override;
binder::Status getOutput(int *output);
+ binder::Status getSpatializedChannelMasks(std::vector<int>* masks) override;
/** IBinder::DeathRecipient. Listen to the death of the INativeSpatializerCallback. */
virtual void binderDied(const wp<IBinder>& who);
@@ -536,6 +537,7 @@
std::vector<media::audio::common::HeadTracking::Mode> mHeadTrackingModes;
std::vector<media::audio::common::Spatialization::Mode> mSpatializationModes;
std::vector<audio_channel_mask_t> mChannelMasks;
+ std::vector<audio_channel_mask_t> mSpatializedChannelMasks;
bool mSupportsHeadTracking;
/** List of supported head tracking connection modes reported by the spatializer.
diff --git a/services/audiopolicy/tests/Android.bp b/services/audiopolicy/tests/Android.bp
index 182dc61..a6e5c75 100644
--- a/services/audiopolicy/tests/Android.bp
+++ b/services/audiopolicy/tests/Android.bp
@@ -21,6 +21,7 @@
],
shared_libs: [
+ "audiopolicy-aidl-cpp",
"framework-permission-aidl-cpp",
"libaudioclient",
"libaudiofoundation",
@@ -32,6 +33,7 @@
"libhidlbase",
"liblog",
"libmedia_helper",
+ "libstagefright_foundation",
"libutils",
"libxml2",
"server_configurable_flags",
@@ -42,6 +44,7 @@
"audioclient-types-aidl-cpp",
"com.android.media.audio-aconfig-cc",
"com.android.media.audioserver-aconfig-cc",
+ "libaudio_aidl_conversion_common_cpp",
"libaudiopolicycomponents",
"libflagtest",
"libgmock",
diff --git a/services/audiopolicy/tests/AudioPolicyTestClient.h b/services/audiopolicy/tests/AudioPolicyTestClient.h
index 33dc5fe..8e5fb96 100644
--- a/services/audiopolicy/tests/AudioPolicyTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyTestClient.h
@@ -128,6 +128,10 @@
std::vector<media::audio::common::AudioMMapPolicyInfo>* /*policyInfos*/) override {
return INVALID_OPERATION;
}
+ error::BinderResult<bool> checkPermissionForInput(const AttributionSourceState& /* attr */,
+ const PermissionReqs& /* req */) {
+ return true;
+ }
};
} // namespace android
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index f8f91fc..a8f79c3 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -97,13 +97,6 @@
attributionSourceState.token = sp<BBinder>::make();
return attributionSourceState;
}
-
-bool equals(const audio_config_base_t& config1, const audio_config_base_t& config2) {
- return config1.format == config2.format
- && config1.sample_rate == config2.sample_rate
- && config1.channel_mask == config2.channel_mask;
-}
-
} // namespace
TEST(AudioPolicyConfigTest, DefaultConfigForTestsIsEmpty) {
@@ -341,12 +334,15 @@
if (!portId) portId = &localPortId;
*portId = AUDIO_PORT_HANDLE_NONE;
if (!virtualDeviceId) virtualDeviceId = 0;
- AudioPolicyInterface::input_type_t inputType;
AttributionSourceState attributionSource = createAttributionSourceState(/*uid=*/ 0);
- ASSERT_EQ(OK, mManager->getInputForAttr(
- &attr, input, riid, session, attributionSource, &config, flags,
- selectedDeviceId, &inputType, portId, virtualDeviceId));
- ASSERT_NE(AUDIO_PORT_HANDLE_NONE, *portId);
+ auto inputRes = mManager->getInputForAttr(attr, *input, *selectedDeviceId,
+ config, flags, riid, session, attributionSource);
+ ASSERT_TRUE(inputRes.has_value());
+ ASSERT_NE(inputRes->portId, AUDIO_PORT_HANDLE_NONE);
+ *input = inputRes->input;
+ if (selectedDeviceId != nullptr) *selectedDeviceId = inputRes->selectedDeviceId;
+ *portId = inputRes->portId;
+ if (virtualDeviceId != nullptr) *virtualDeviceId = inputRes->virtualDeviceId;
}
void AudioPolicyManagerTest::getAudioPorts(audio_port_type_t type, audio_port_role_t role,
@@ -1231,40 +1227,39 @@
AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
"", "", AUDIO_FORMAT_DEFAULT));
- audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+ const audio_port_handle_t requestedDeviceId = AUDIO_PORT_HANDLE_NONE;
+ const audio_io_handle_t requestedInput = AUDIO_PORT_HANDLE_NONE;
+ const AttributionSourceState attributionSource = createAttributionSourceState(/*uid=*/ 0);
+ AudioPolicyInterface::input_type_t inputType;
+
audio_attributes_t attr = {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
AUDIO_SOURCE_VOICE_COMMUNICATION,AUDIO_FLAG_NONE, ""};
- AudioPolicyInterface::input_type_t inputType;
- audio_io_handle_t input = AUDIO_PORT_HANDLE_NONE;
- AttributionSourceState attributionSource = createAttributionSourceState(/*uid=*/ 0);
audio_config_base_t requestedConfig = {
.sample_rate = k48000SamplingRate,
.channel_mask = AUDIO_CHANNEL_IN_STEREO,
.format = AUDIO_FORMAT_PCM_16_BIT,
};
- audio_config_base_t config = requestedConfig;
- audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
- uint32_t *virtualDeviceId = 0;
- ASSERT_EQ(OK, mManager->getInputForAttr(
- &attr, &input, 1 /*riid*/, AUDIO_SESSION_NONE, attributionSource, &config,
- AUDIO_INPUT_FLAG_NONE,
- &selectedDeviceId, &inputType, &portId, virtualDeviceId));
- ASSERT_NE(AUDIO_PORT_HANDLE_NONE, portId);
- ASSERT_TRUE(equals(requestedConfig, config));
+ auto inputRes = mManager->getInputForAttr(attr, requestedInput, requestedDeviceId,
+ requestedConfig, AUDIO_INPUT_FLAG_NONE, 1 /*riid*/,
+ AUDIO_SESSION_NONE, attributionSource);
+ ASSERT_TRUE(inputRes.has_value());
+ ASSERT_NE(inputRes->portId, AUDIO_PORT_HANDLE_NONE);
+ ASSERT_EQ(VALUE_OR_FATAL(legacy2aidl_audio_config_base_t_AudioConfigBase(
+ requestedConfig, true /* isInput */)),
+ inputRes->config);
attr = {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
AUDIO_SOURCE_VOICE_COMMUNICATION, AUDIO_FLAG_NONE, ""};
requestedConfig.channel_mask = deviceChannelMask;
- config = requestedConfig;
- selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
- input = AUDIO_PORT_HANDLE_NONE;
- portId = AUDIO_PORT_HANDLE_NONE;
- ASSERT_EQ(OK, mManager->getInputForAttr(
- &attr, &input, 1 /*riid*/, AUDIO_SESSION_NONE, attributionSource, &config,
- AUDIO_INPUT_FLAG_NONE,
- &selectedDeviceId, &inputType, &portId, virtualDeviceId));
- ASSERT_NE(AUDIO_PORT_HANDLE_NONE, portId);
- ASSERT_TRUE(equals(requestedConfig, config));
+
+ inputRes = mManager->getInputForAttr(attr, requestedInput, requestedDeviceId, requestedConfig,
+ AUDIO_INPUT_FLAG_NONE, 1 /*riid*/, AUDIO_SESSION_NONE,
+ attributionSource);
+ ASSERT_TRUE(inputRes.has_value());
+ ASSERT_NE(inputRes->portId, AUDIO_PORT_HANDLE_NONE);
+ ASSERT_EQ(VALUE_OR_FATAL(legacy2aidl_audio_config_base_t_AudioConfigBase(requestedConfig,
+ true /* isInput */)),
+ inputRes->config);
ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(AUDIO_DEVICE_IN_USB_DEVICE,
AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp
index b9c8206..b44f949 100644
--- a/services/camera/libcameraservice/Android.bp
+++ b/services/camera/libcameraservice/Android.bp
@@ -87,7 +87,9 @@
"android.hardware.camera.device@3.6",
"android.hardware.camera.device@3.7",
"android.hardware.common-V2-ndk",
+ "android.hardware.common-V2-cpp",
"android.hardware.common.fmq-V1-ndk",
+ "android.hardware.common.fmq-V1-cpp",
"camera_platform_flags_c_lib",
"com.android.window.flags.window-aconfig_flags_c_lib",
"media_permission-aidl-cpp",
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index df94478..fdb5b7d 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -1492,6 +1492,7 @@
int servicePid, std::pair<int, IPCTransport> deviceVersionAndTransport,
apiLevel effectiveApiLevel, bool overrideForPerfClass, int rotationOverride,
bool forceSlowJpegMode, const std::string& originalCameraId, bool sharedMode,
+ bool isVendorClient,
/*out*/sp<BasicClient>* client) {
// For HIDL devices
if (deviceVersionAndTransport.second == IPCTransport::HIDL) {
@@ -1537,7 +1538,8 @@
cameraService, tmp, cameraService->mCameraServiceProxyWrapper,
cameraService->mAttributionAndPermissionUtils, clientAttribution, callingPid,
systemNativeClient, cameraId, facing, sensorOrientation, servicePid,
- overrideForPerfClass, rotationOverride, originalCameraId, sharedMode);
+ overrideForPerfClass, rotationOverride, originalCameraId, sharedMode,
+ isVendorClient);
ALOGI("%s: Camera2 API, rotationOverride %d", __FUNCTION__, rotationOverride);
}
return Status::ok();
@@ -1638,7 +1640,7 @@
/*rotationOverride*/
hardware::ICameraService::ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT,
/*forceSlowJpegMode*/ false, cameraIdStr, /*isNonSystemNdk*/ false,
- /*sharedMode*/false, /*out*/ tmp))
+ /*sharedMode*/false, /*isVendorClient*/false,/*out*/ tmp))
.isOk()) {
ALOGE("%s: Error initializing shim metadata: %s", __FUNCTION__, ret.toString8().c_str());
}
@@ -2202,7 +2204,8 @@
cameraClient, cameraIdStr, api1CameraId, resolvedClientAttribution,
/*systemNativeClient*/ false, API_1,
/*shimUpdateOnly*/ false, /*oomScoreOffset*/ 0, targetSdkVersion, rotationOverride,
- forceSlowJpegMode, cameraIdStr, isNonSystemNdk, /*sharedMode*/false, /*out*/ client);
+ forceSlowJpegMode, cameraIdStr, isNonSystemNdk, /*sharedMode*/false,
+ /*isVendorClient*/ false, /*out*/ client);
if (!ret.isOk()) {
logRejected(cameraIdStr, getCallingPid(),
@@ -2286,7 +2289,32 @@
const std::string& unresolvedCameraId,
int oomScoreOffset, int targetSdkVersion,
int rotationOverride, const AttributionSourceState& clientAttribution, int32_t devicePolicy,
- bool sharedMode, /*out*/sp<hardware::camera2::ICameraDeviceUser>* device) {
+ bool sharedMode,
+ /*out*/sp<hardware::camera2::ICameraDeviceUser>* device) {
+ return connectDeviceImpl(cameraCb, unresolvedCameraId, oomScoreOffset, targetSdkVersion,
+ rotationOverride, clientAttribution, devicePolicy, sharedMode,
+ /*isVendorClient*/false, device);
+}
+
+Status CameraService::connectDeviceVendor(
+ const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb,
+ const std::string& unresolvedCameraId,
+ int oomScoreOffset, int targetSdkVersion,
+ int rotationOverride, const AttributionSourceState& clientAttribution, int32_t devicePolicy,
+ bool sharedMode,
+ /*out*/sp<hardware::camera2::ICameraDeviceUser>* device) {
+ return connectDeviceImpl(cameraCb, unresolvedCameraId, oomScoreOffset, targetSdkVersion,
+ rotationOverride, clientAttribution, devicePolicy, sharedMode,
+ /*isVendorClient*/true, device);
+}
+
+Status CameraService::connectDeviceImpl(
+ const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb,
+ const std::string& unresolvedCameraId,
+ int oomScoreOffset, int targetSdkVersion,
+ int rotationOverride, const AttributionSourceState& clientAttribution, int32_t devicePolicy,
+ bool sharedMode, bool isVendorClient,
+ /*out*/sp<hardware::camera2::ICameraDeviceUser>* device) {
ATRACE_CALL();
RunThreadWithRealtimePriority priorityBump;
Status ret = Status::ok();
@@ -2367,7 +2395,7 @@
cameraCb, cameraId, /*api1CameraId*/ -1, resolvedClientAttribution, systemNativeClient,
API_2, /*shimUpdateOnly*/ false, oomScoreOffset, targetSdkVersion, rotationOverride,
/*forceSlowJpegMode*/ false, unresolvedCameraId, isNonSystemNdk, sharedMode,
- /*out*/ client);
+ isVendorClient, /*out*/ client);
if (!ret.isOk()) {
logRejected(cameraId, clientPid, clientPackageName, toStdString(ret.toString8()));
@@ -2447,7 +2475,8 @@
bool shimUpdateOnly, int oomScoreOffset, int targetSdkVersion,
int rotationOverride, bool forceSlowJpegMode,
const std::string& originalCameraId, bool isNonSystemNdk,
- bool sharedMode, /*out*/ sp<CLIENT>& device) {
+ bool sharedMode, bool isVendorClient,
+ /*out*/ sp<CLIENT>& device) {
binder::Status ret = binder::Status::ok();
nsecs_t openTimeNs = systemTime();
@@ -2546,7 +2575,7 @@
systemNativeClient, cameraId, api1CameraId, facing, orientation,
getpid(), deviceVersionAndTransport, effectiveApiLevel,
overrideForPerfClass, rotationOverride, forceSlowJpegMode,
- originalCameraId, sharedMode,
+ originalCameraId, sharedMode, isVendorClient,
/*out*/ &tmp))
.isOk()) {
return ret;
@@ -3811,14 +3840,31 @@
const std::string& cameraId) {
// Remove from active clients list
std::vector<sp<CameraService::BasicClient>> clients;
- std::vector<CameraService::DescriptorPtr> clientDescriptors;
- clientDescriptors = mActiveClientManager.removeAll(cameraId);
- for (const auto& clientDescriptorPtr : clientDescriptors) {
+ if (flags::camera_multi_client()) {
+ std::vector<CameraService::DescriptorPtr> clientDescriptors;
+ clientDescriptors = mActiveClientManager.removeAll(cameraId);
+ for (const auto& clientDescriptorPtr : clientDescriptors) {
+ if (clientDescriptorPtr != nullptr) {
+ sp<BasicClient> client = clientDescriptorPtr->getValue();
+ if (client.get() != nullptr) {
+ cacheClientTagDumpIfNeeded(clientDescriptorPtr->getKey(), client.get());
+ clients.push_back(client);
+ }
+ }
+ }
+ } else {
+ auto clientDescriptorPtr = mActiveClientManager.remove(cameraId);
+ if (clientDescriptorPtr == nullptr) {
+ ALOGW("%s: Could not evict client, no client for camera ID %s", __FUNCTION__,
+ cameraId.c_str());
+ return clients;
+ }
+
sp<BasicClient> client = clientDescriptorPtr->getValue();
if (client.get() != nullptr) {
cacheClientTagDumpIfNeeded(clientDescriptorPtr->getKey(), client.get());
+ clients.push_back(client);
}
- clients.push_back(client);
}
return clients;
}
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 9c75ede..c4d2d67 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -280,6 +280,14 @@
std::vector<hardware::CameraStatus>* cameraStatuses, bool isVendor = false,
bool isProcessLocalTest = false);
+ binder::Status connectDeviceVendor(
+ const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb,
+ const std::string& cameraId, int scoreOffset, int targetSdkVersion,
+ int rotationOverride, const AttributionSourceState& clientAttribution,
+ int32_t devicePolicy, bool sharedMode,
+ /*out*/
+ sp<hardware::camera2::ICameraDeviceUser>* device);
+
// Monitored UIDs availability notification
void notifyMonitoredUids();
void notifyMonitoredUids(const std::unordered_set<uid_t> ¬ifyUidSet);
@@ -631,6 +639,9 @@
CameraClientManager();
virtual ~CameraClientManager();
+ // Bring all remove() functions into scope
+ using ClientManager::remove;
+
virtual void remove(const DescriptorPtr& value) override;
/**
@@ -993,7 +1004,16 @@
bool shimUpdateOnly, int scoreOffset, int targetSdkVersion,
int rotationOverride, bool forceSlowJpegMode,
const std::string& originalCameraId, bool isNonSystemNdk,
- bool sharedMode, /*out*/ sp<CLIENT>& device);
+ bool sharedMode, bool isVendorClient,
+ /*out*/ sp<CLIENT>& device);
+
+ binder::Status connectDeviceImpl(
+ const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb,
+ const std::string& cameraId, int scoreOffset, int targetSdkVersion,
+ int rotationOverride, const AttributionSourceState& clientAttribution,
+ int32_t devicePolicy, bool sharedMode, bool isVendorClient,
+ /*out*/
+ sp<hardware::camera2::ICameraDeviceUser>* device);
// Lock guarding camera service state
Mutex mServiceLock;
@@ -1490,6 +1510,7 @@
apiLevel effectiveApiLevel, bool overrideForPerfClass,
int rotationOverride, bool forceSlowJpegMode,
const std::string& originalCameraId, bool sharedMode,
+ bool isVendorClient,
/*out*/ sp<BasicClient>* client);
static std::string toString(std::set<userid_t> intSet);
diff --git a/services/camera/libcameraservice/FwkOnlyMetadataTags.h b/services/camera/libcameraservice/FwkOnlyMetadataTags.h
new file mode 100644
index 0000000..768afeb
--- /dev/null
+++ b/services/camera/libcameraservice/FwkOnlyMetadataTags.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <array>
+#pragma once
+
+/**
+ * ! Do not edit this file directly !
+ *
+ * Generated automatically from fwk_only_metadata_tags.mako. To be included in libcameraservice
+ * only by Camera3Device.cpp.
+ */
+
+namespace android {
+
+/**
+ * Framework only CaptureRequest keys. To be used for filtering out keys in CaptureRequest
+ * before sending to the HAL.
+ */
+constexpr std::array kFwkOnlyMetadataKeys = {
+ ANDROID_CONTROL_AF_REGIONS_SET,
+ ANDROID_CONTROL_AE_REGIONS_SET,
+ ANDROID_CONTROL_AWB_REGIONS_SET,
+ ANDROID_CONTROL_ZOOM_METHOD,
+ ANDROID_SCALER_CROP_REGION_SET,
+ ANDROID_EXTENSION_STRENGTH,
+};
+
+} //namespace android
diff --git a/services/camera/libcameraservice/aidl/AidlCameraDeviceCallbacks.cpp b/services/camera/libcameraservice/aidl/AidlCameraDeviceCallbacks.cpp
index 70647b4..950ea05 100644
--- a/services/camera/libcameraservice/aidl/AidlCameraDeviceCallbacks.cpp
+++ b/services/camera/libcameraservice/aidl/AidlCameraDeviceCallbacks.cpp
@@ -174,11 +174,19 @@
}
binder::Status AidlCameraDeviceCallbacks::onResultReceived(
- const CameraMetadataNative& result,
+ const CameraMetadataInfo &resultInfo,
const UCaptureResultExtras& resultExtras,
const ::std::vector<UPhysicalCaptureResultInfo>& physicalCaptureResultInfos) {
// Wrap CameraMetadata, resultExtras and physicalCaptureResultInfos in on
// sp<RefBase>-able structure and post it.
+ // We modify metadata - since we want to filter out tags based on the vndk
+ // version, and also this communication is an in process function call.
+ // So we don't use FMQ for the shim layer. FMQ is still used for VNDK IPC.
+ if (resultInfo.getTag() != CameraMetadataInfo::metadata) {
+ ALOGE("Vendor callbacks got metadata in fmq ? ");
+ return binder::Status::ok();
+ }
+ const CameraMetadataNative &result = resultInfo.get<CameraMetadataInfo::metadata>();
sp<ResultWrapper> resultWrapper = new ResultWrapper(const_cast<CameraMetadataNative &>(result),
resultExtras, physicalCaptureResultInfos);
sp<AMessage> msg = new AMessage(kWhatResultReceived, mHandler);
diff --git a/services/camera/libcameraservice/aidl/AidlCameraDeviceCallbacks.h b/services/camera/libcameraservice/aidl/AidlCameraDeviceCallbacks.h
index 07bf7d8..6504cdc 100644
--- a/services/camera/libcameraservice/aidl/AidlCameraDeviceCallbacks.h
+++ b/services/camera/libcameraservice/aidl/AidlCameraDeviceCallbacks.h
@@ -46,6 +46,7 @@
using ::android::frameworks::cameraservice::utils::DeathPipe;
using ::android::hardware::camera2::impl::CameraMetadataNative;
+using CameraMetadataInfo = android::hardware::camera2::CameraMetadataInfo;
using CaptureResultMetadataQueue = AidlMessageQueue<int8_t, SynchronizedReadWrite>;
class AidlCameraDeviceCallbacks : public UBnCameraDeviceCallbacks {
@@ -65,7 +66,8 @@
int64_t timestamp) override;
binder::Status onResultReceived(
- const CameraMetadataNative& result, const CaptureResultExtras& resultExtras,
+ const CameraMetadataInfo &resultInfo,
+ const CaptureResultExtras& resultExtras,
const std::vector<PhysicalCaptureResultInfo>& physicalCaptureResultInfos) override;
binder::Status onPrepared(int32_t streamId) override;
diff --git a/services/camera/libcameraservice/aidl/AidlCameraService.cpp b/services/camera/libcameraservice/aidl/AidlCameraService.cpp
index a2c431e..46e2280 100644
--- a/services/camera/libcameraservice/aidl/AidlCameraService.cpp
+++ b/services/camera/libcameraservice/aidl/AidlCameraService.cpp
@@ -177,7 +177,7 @@
kDefaultDeviceId);
clientAttribution.packageName = "";
clientAttribution.attributionTag = std::nullopt;
- binder::Status serviceRet = mCameraService->connectDevice(
+ binder::Status serviceRet = mCameraService->connectDeviceVendor(
callbacks,
in_cameraId,
/* scoreOffset= */ 0,
diff --git a/services/camera/libcameraservice/aidl/AidlUtils.cpp b/services/camera/libcameraservice/aidl/AidlUtils.cpp
index 1ec5072..7f927f1 100644
--- a/services/camera/libcameraservice/aidl/AidlUtils.cpp
+++ b/services/camera/libcameraservice/aidl/AidlUtils.cpp
@@ -24,6 +24,7 @@
#include <aidlcommonsupport/NativeHandle.h>
#include <camera/StringUtils.h>
#include <device3/Camera3StreamInterface.h>
+#include <gui/Flags.h> // remove with WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
#include <mediautils/AImageReaderUtils.h>
#include "utils/Utils.h"
@@ -32,6 +33,7 @@
using aimg::AImageReader_getHGBPFromHandle;
using hardware::graphics::bufferqueue::V1_0::utils::H2BGraphicBufferProducer;
+using CameraMetadataInfo = android::hardware::camera2::CameraMetadataInfo;
// Note: existing data in dst will be gone. Caller still owns the memory of src
void cloneToAidl(const camera_metadata_t* src, SCameraMetadata* dst) {
@@ -76,20 +78,25 @@
}
UOutputConfiguration convertFromAidl(const SOutputConfiguration &src) {
- std::vector<sp<IGraphicBufferProducer>> iGBPs;
+ std::vector<ParcelableSurfaceType> pSurfaces;
if (!src.surfaces.empty()) {
auto& surfaces = src.surfaces;
- iGBPs.reserve(surfaces.size());
+ pSurfaces.reserve(surfaces.size());
for (auto& sSurface : surfaces) {
- sp<IGraphicBufferProducer> igbp =
- Surface::getIGraphicBufferProducer(sSurface.get());
- if (igbp == nullptr) {
- ALOGE("%s: ANativeWindow (%p) not backed by a Surface.",
- __FUNCTION__, sSurface.get());
+ ParcelableSurfaceType pSurface;
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+ pSurface.graphicBufferProducer = Surface::getIGraphicBufferProducer(sSurface.get());
+ if (pSurface.isEmpty()) {
+#else
+ pSurface = Surface::getIGraphicBufferProducer(sSurface.get());
+ if (pSurface == nullptr) {
+#endif
+ ALOGE("%s: ANativeWindow (%p) not backed by a Surface.", __FUNCTION__,
+ sSurface.get());
continue;
}
- iGBPs.push_back(igbp);
+ pSurfaces.push_back(pSurface);
}
} else {
#pragma clang diagnostic push
@@ -100,7 +107,7 @@
auto &windowHandles = src.windowHandles;
#pragma clang diagnostic pop
- iGBPs.reserve(windowHandles.size());
+ pSurfaces.reserve(windowHandles.size());
for (auto &handle : windowHandles) {
native_handle_t* nh = makeFromAidl(handle);
@@ -111,15 +118,20 @@
continue;
}
- iGBPs.push_back(new H2BGraphicBufferProducer(igbp));
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+ view::Surface viewSurface;
+ viewSurface.graphicBufferProducer = new H2BGraphicBufferProducer(igbp);
+ pSurfaces.push_back(viewSurface);
+#else
+ pSurfaces.push_back(new H2BGraphicBufferProducer(igbp));
+#endif
native_handle_delete(nh);
}
}
UOutputConfiguration outputConfiguration(
- iGBPs, convertFromAidl(src.rotation), src.physicalCameraId,
- src.windowGroupId, OutputConfiguration::SURFACE_TYPE_UNKNOWN, 0, 0,
- (iGBPs.size() > 1));
+ pSurfaces, convertFromAidl(src.rotation), src.physicalCameraId, src.windowGroupId,
+ OutputConfiguration::SURFACE_TYPE_UNKNOWN, 0, 0, (pSurfaces.size() > 1));
return outputConfiguration;
}
@@ -254,7 +266,8 @@
SPhysicalCaptureResultInfo dst;
dst.physicalCameraId = src.mPhysicalCameraId;
- const camera_metadata_t *rawMetadata = src.mPhysicalCameraMetadata.getAndLock();
+ const camera_metadata_t *rawMetadata =
+ src.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>().getAndLock();
// Try using fmq at first.
size_t metadata_size = get_camera_metadata_size(rawMetadata);
if ((metadata_size > 0) && (fmq->availableToWrite() > 0)) {
@@ -267,7 +280,7 @@
dst.physicalCameraMetadata.set<SCaptureMetadataInfo::metadata>(std::move(metadata));
}
}
- src.mPhysicalCameraMetadata.unlock(rawMetadata);
+ src.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>().unlock(rawMetadata);
return dst;
}
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 8c30d54..5bcb8e8 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -16,17 +16,22 @@
#define LOG_TAG "CameraDeviceClient"
#define ATRACE_TAG ATRACE_TAG_CAMERA
+#ifdef LOG_NNDEBUG
+#define ALOGVV(...) ALOGV(__VA_ARGS__)
+#else
+#define ALOGVV(...) ((void)0)
+#endif
//#define LOG_NDEBUG 0
+#include <camera/CameraUtils.h>
+#include <camera/StringUtils.h>
+#include <camera/camera2/CaptureRequest.h>
#include <com_android_internal_camera_flags.h>
#include <cutils/properties.h>
+#include <gui/Surface.h>
#include <utils/Log.h>
#include <utils/SessionConfigurationUtils.h>
#include <utils/Trace.h>
-#include <gui/Surface.h>
-#include <camera/camera2/CaptureRequest.h>
-#include <camera/CameraUtils.h>
-#include <camera/StringUtils.h>
#include "common/CameraDeviceBase.h"
#include "device3/Camera3Device.h"
@@ -40,6 +45,7 @@
#include "JpegRCompositeStream.h"
// Convenience methods for constructing binder::Status objects for error returns
+constexpr int32_t METADATA_QUEUE_SIZE = 1 << 20;
#define STATUS_ERROR(errorCode, errorString) \
binder::Status::fromServiceSpecificError(errorCode, \
@@ -80,7 +86,7 @@
const AttributionSourceState& clientAttribution, int callingPid, bool systemNativeClient,
const std::string& cameraId, int cameraFacing, int sensorOrientation, int servicePid,
bool overrideForPerfClass, int rotationOverride, const std::string& originalCameraId,
- bool sharedMode)
+ bool sharedMode, bool isVendorClient)
: Camera2ClientBase(cameraService, remoteCallback, cameraServiceProxyWrapper,
attributionAndPermissionUtils, clientAttribution, callingPid,
systemNativeClient, cameraId, /*API1 camera ID*/ -1, cameraFacing,
@@ -90,7 +96,8 @@
mStreamingRequestId(REQUEST_ID_NONE),
mRequestIdCounter(0),
mOverrideForPerfClass(overrideForPerfClass),
- mOriginalCameraId(originalCameraId) {
+ mOriginalCameraId(originalCameraId),
+ mIsVendorClient(isVendorClient) {
ATRACE_CALL();
ALOGI("CameraDeviceClient %s: Opened", cameraId.c_str());
}
@@ -180,6 +187,14 @@
mHighResolutionSensors.insert(physicalId);
}
}
+ int32_t resultMQSize =
+ property_get_int32("ro.vendor.camera.res.fmq.size", /*default*/METADATA_QUEUE_SIZE);
+ res = CreateMetadataQueue(&mResultMetadataQueue, resultMQSize);
+ if (res != OK) {
+ ALOGE("%s: Creating result metadata queue failed: %s(%d)", __FUNCTION__,
+ strerror(-res), res);
+ return res;
+ }
return OK;
}
@@ -195,10 +210,44 @@
return submitRequestList(requestList, streaming, submitInfo);
}
-binder::Status CameraDeviceClient::insertGbpLocked(const sp<IGraphicBufferProducer>& gbp,
+status_t CameraDeviceClient::getSurfaceKey(ParcelableSurfaceType surface, SurfaceKey* out) const {
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+ auto ret = surface.getUniqueId(out);
+ if (ret != OK) {
+ ALOGE("%s: Camera %s: Could not getUniqueId.", __FUNCTION__, mCameraIdStr.c_str());
+ return ret;
+ }
+ return OK;
+#else
+ *out = IInterface::asBinder(surface);
+ return OK;
+#endif
+}
+
+status_t CameraDeviceClient::getSurfaceKey(sp<Surface> surface, SurfaceKey* out) const {
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+ auto ret = surface->getUniqueId(out);
+ if (ret != OK) {
+ ALOGE("%s: Camera %s: Could not getUniqueId.", __FUNCTION__, mCameraIdStr.c_str());
+ return ret;
+ }
+ return OK;
+#else
+ *out = IInterface::asBinder(surface->getIGraphicBufferProducer());
+ return OK;
+#endif
+}
+
+binder::Status CameraDeviceClient::insertSurfaceLocked(const ParcelableSurfaceType& surface,
SurfaceMap* outSurfaceMap, Vector<int32_t>* outputStreamIds, int32_t *currentStreamId) {
int compositeIdx;
- int idx = mStreamMap.indexOfKey(IInterface::asBinder(gbp));
+ SurfaceKey surfaceKey;
+ status_t ret = getSurfaceKey(surface, &surfaceKey);
+ if(ret != OK) {
+ ALOGE("%s: Camera %s: Could not get the SurfaceKey", __FUNCTION__, mCameraIdStr.c_str());
+ return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, "Could not get the SurfaceKey");
+ }
+ int idx = mStreamMap.indexOfKey(surfaceKey);
Mutex::Autolock l(mCompositeLock);
// Trying to submit request with surface that wasn't created
@@ -208,7 +257,7 @@
__FUNCTION__, mCameraIdStr.c_str());
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
"Request targets Surface that is not part of current capture session");
- } else if ((compositeIdx = mCompositeStreamMap.indexOfKey(IInterface::asBinder(gbp)))
+ } else if ((compositeIdx = mCompositeStreamMap.indexOfKey(surfaceKey))
!= NAME_NOT_FOUND) {
mCompositeStreamMap.valueAt(compositeIdx)->insertGbp(outSurfaceMap, outputStreamIds,
currentStreamId);
@@ -332,8 +381,12 @@
if (surface == 0) continue;
int32_t streamId;
- sp<IGraphicBufferProducer> gbp = surface->getIGraphicBufferProducer();
- res = insertGbpLocked(gbp, &surfaceMap, &outputStreamIds, &streamId);
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+ ParcelableSurfaceType surface_type = view::Surface::fromSurface(surface);
+#else
+ ParcelableSurfaceType surface_type = surface->getIGraphicBufferProducer();
+#endif
+ res = insertSurfaceLocked(surface_type, &surfaceMap, &outputStreamIds, &streamId);
if (!res.isOk()) {
return res;
}
@@ -363,8 +416,8 @@
"Request targets Surface that is not part of current capture session");
}
- const auto& gbps = mConfiguredOutputs.valueAt(index).getGraphicBufferProducers();
- if ((size_t)surfaceIdx >= gbps.size()) {
+ const auto& surfaces = mConfiguredOutputs.valueAt(index).getSurfaces();
+ if ((size_t)surfaceIdx >= surfaces.size()) {
ALOGE("%s: Camera %s: Tried to submit a request with a surface that"
" we have not called createStream on: stream %d, surfaceIdx %d",
__FUNCTION__, mCameraIdStr.c_str(), streamId, surfaceIdx);
@@ -372,7 +425,9 @@
"Request targets Surface has invalid surface index");
}
- res = insertGbpLocked(gbps[surfaceIdx], &surfaceMap, &outputStreamIds, nullptr);
+ res = insertSurfaceLocked(surfaces[surfaceIdx], &surfaceMap, &outputStreamIds,
+ nullptr);
+
if (!res.isOk()) {
return res;
}
@@ -787,7 +842,7 @@
}
bool isInput = false;
- std::vector<sp<IBinder>> surfaces;
+ std::vector<SurfaceKey> surfaces;
std::vector<size_t> removedSurfaceIds;
ssize_t dIndex = NAME_NOT_FOUND;
ssize_t compositeIndex = NAME_NOT_FOUND;
@@ -899,13 +954,12 @@
"OutputConfiguration isn't valid!");
}
- const std::vector<sp<IGraphicBufferProducer>>& bufferProducers =
- outputConfiguration.getGraphicBufferProducers();
- size_t numBufferProducers = bufferProducers.size();
+ const std::vector<ParcelableSurfaceType>& surfaces = outputConfiguration.getSurfaces();
+ size_t numSurfaces = surfaces.size();
bool deferredConsumer = outputConfiguration.isDeferred();
bool isShared = outputConfiguration.isShared();
const std::string &physicalCameraId = outputConfiguration.getPhysicalCameraId();
- bool deferredConsumerOnly = deferredConsumer && numBufferProducers == 0;
+ bool deferredConsumerOnly = deferredConsumer && numSurfaces == 0;
bool isMultiResolution = outputConfiguration.isMultiResolution();
int64_t dynamicRangeProfile = outputConfiguration.getDynamicRangeProfile();
int64_t streamUseCase = outputConfiguration.getStreamUseCase();
@@ -913,7 +967,7 @@
int32_t colorSpace = outputConfiguration.getColorSpace();
bool useReadoutTimestamp = outputConfiguration.useReadoutTimestamp();
- res = SessionConfigurationUtils::checkSurfaceType(numBufferProducers, deferredConsumer,
+ res = SessionConfigurationUtils::checkSurfaceType(numSurfaces, deferredConsumer,
outputConfiguration.getSurfaceType(), /*isConfigurationComplete*/true);
if (!res.isOk()) {
return res;
@@ -928,8 +982,8 @@
return res;
}
- std::vector<SurfaceHolder> surfaces;
- std::vector<sp<IBinder>> binders;
+ std::vector<SurfaceHolder> surfaceHolders;
+ std::vector<SurfaceKey> surfaceKeys;
std::vector<OutputStreamInfo> streamInfos;
status_t err;
@@ -942,10 +996,19 @@
bool isStreamInfoValid = false;
const std::vector<int32_t> &sensorPixelModesUsed =
outputConfiguration.getSensorPixelModesUsed();
- for (auto& bufferProducer : bufferProducers) {
+
+ for (auto& surface : surfaces) {
// Don't create multiple streams for the same target surface
- sp<IBinder> binder = IInterface::asBinder(bufferProducer);
- ssize_t index = mStreamMap.indexOfKey(binder);
+ SurfaceKey surfaceKey;
+ status_t ret = getSurfaceKey(surface, &surfaceKey);
+ if(ret != OK) {
+ ALOGE("%s: Camera %s: Could not get the SurfaceKey", __FUNCTION__,
+ mCameraIdStr.c_str());
+ return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION,
+ "Could not get the SurfaceKey");
+ }
+
+ ssize_t index = mStreamMap.indexOfKey(surfaceKey);
if (index != NAME_NOT_FOUND) {
std::string msg = std::string("Camera ") + mCameraIdStr
+ ": Surface already has a stream created for it (ID "
@@ -954,10 +1017,14 @@
return STATUS_ERROR(CameraService::ERROR_ALREADY_EXISTS, msg.c_str());
}
- int mirrorMode = outputConfiguration.getMirrorMode(bufferProducer);
- sp<Surface> surface;
+ int mirrorMode = outputConfiguration.getMirrorMode(surface);
+ sp<Surface> outSurface;
res = SessionConfigurationUtils::createSurfaceFromGbp(streamInfo,
- isStreamInfoValid, surface, bufferProducer, mCameraIdStr,
+ isStreamInfoValid, outSurface, surface
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+ .graphicBufferProducer
+#endif
+ , mCameraIdStr,
mDevice->infoPhysical(physicalCameraId), sensorPixelModesUsed, dynamicRangeProfile,
streamUseCase, timestampBase, mirrorMode, colorSpace, /*respectSurfaceSize*/false);
@@ -968,8 +1035,8 @@
isStreamInfoValid = true;
}
- binders.push_back(IInterface::asBinder(bufferProducer));
- surfaces.push_back({surface, mirrorMode});
+ surfaceKeys.push_back(surfaceKey);
+ surfaceHolders.push_back({outSurface, mirrorMode});
if (flags::camera_multi_client() && mSharedMode) {
streamInfos.push_back(streamInfo);
}
@@ -980,15 +1047,15 @@
if (flags::camera_multi_client() && mSharedMode) {
err = mDevice->getSharedStreamId(outputConfiguration, &streamId);
if (err == OK) {
- err = mDevice->addSharedSurfaces(streamId, streamInfos, surfaces, &surfaceIds);
+ err = mDevice->addSharedSurfaces(streamId, streamInfos, surfaceHolders, &surfaceIds);
}
} else {
bool isDepthCompositeStream =
- camera3::DepthCompositeStream::isDepthCompositeStream(surfaces[0].mSurface);
+ camera3::DepthCompositeStream::isDepthCompositeStream(surfaceHolders[0].mSurface);
bool isHeicCompositeStream = camera3::HeicCompositeStream::isHeicCompositeStream(
- surfaces[0].mSurface);
+ surfaceHolders[0].mSurface);
bool isJpegRCompositeStream =
- camera3::JpegRCompositeStream::isJpegRCompositeStream(surfaces[0].mSurface) &&
+ camera3::JpegRCompositeStream::isJpegRCompositeStream(surfaceHolders[0].mSurface) &&
!mDevice->isCompositeJpegRDisabled();
if (isDepthCompositeStream || isHeicCompositeStream || isJpegRCompositeStream) {
sp<CompositeStream> compositeStream;
@@ -999,7 +1066,7 @@
} else {
compositeStream = new camera3::JpegRCompositeStream(mDevice, getRemoteCallback());
}
- err = compositeStream->createStream(surfaces, deferredConsumer, streamInfo.width,
+ err = compositeStream->createStream(surfaceHolders, deferredConsumer, streamInfo.width,
streamInfo.height, streamInfo.format,
static_cast<camera_stream_rotation_t>(outputConfiguration.getRotation()),
&streamId, physicalCameraId, streamInfo.sensorPixelModesUsed, &surfaceIds,
@@ -1008,12 +1075,18 @@
useReadoutTimestamp);
if (err == OK) {
Mutex::Autolock l(mCompositeLock);
- mCompositeStreamMap.add(
- IInterface::asBinder(surfaces[0].mSurface->getIGraphicBufferProducer()),
- compositeStream);
+ SurfaceKey surfaceKey;
+ status_t ret = getSurfaceKey(surfaceHolders[0].mSurface, &surfaceKey);
+ if(ret != OK) {
+ ALOGE("%s: Camera %s: Could not get the SurfaceKey", __FUNCTION__,
+ mCameraIdStr.c_str());
+ return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION,
+ "Could not get the SurfaceKey");
+ }
+ mCompositeStreamMap.add(surfaceKey, compositeStream);
}
} else {
- err = mDevice->createStream(surfaces, deferredConsumer, streamInfo.width,
+ err = mDevice->createStream(surfaceHolders, deferredConsumer, streamInfo.width,
streamInfo.height, streamInfo.format, streamInfo.dataSpace,
static_cast<camera_stream_rotation_t>(outputConfiguration.getRotation()),
&streamId, physicalCameraId, streamInfo.sensorPixelModesUsed, &surfaceIds,
@@ -1030,10 +1103,15 @@
static_cast<int>(streamInfo.dataSpace), strerror(-err), err);
} else {
int i = 0;
- for (auto& binder : binders) {
- ALOGV("%s: mStreamMap add binder %p streamId %d, surfaceId %d",
- __FUNCTION__, binder.get(), streamId, i);
- mStreamMap.add(binder, StreamSurfaceId(streamId, surfaceIds[i]));
+ for (auto& surfaceKey : surfaceKeys) {
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+ ALOGV("%s: mStreamMap add surfaceKey %lu streamId %d, surfaceId %d",
+ __FUNCTION__, surfaceKey, streamId, i);
+#else
+ ALOGV("%s: mStreamMap add surfaceKey %p streamId %d, surfaceId %d",
+ __FUNCTION__, surfaceKey.get(), streamId, i);
+#endif
+ mStreamMap.add(surfaceKey, StreamSurfaceId(streamId, surfaceIds[i]));
i++;
}
@@ -1257,40 +1335,52 @@
"OutputConfiguration isn't valid!");
}
- const std::vector<sp<IGraphicBufferProducer> >& bufferProducers =
- outputConfiguration.getGraphicBufferProducers();
- const std::string &physicalCameraId = outputConfiguration.getPhysicalCameraId();
+ const std::vector<ParcelableSurfaceType>& surfaces = outputConfiguration.getSurfaces();
+ const std::string& physicalCameraId = outputConfiguration.getPhysicalCameraId();
- auto producerCount = bufferProducers.size();
+ auto producerCount = surfaces.size();
if (producerCount == 0) {
- ALOGE("%s: bufferProducers must not be empty", __FUNCTION__);
+ ALOGE("%s: surfaces must not be empty", __FUNCTION__);
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
- "bufferProducers must not be empty");
+ "surfaces must not be empty");
}
// The first output is the one associated with the output configuration.
// It should always be present, valid and the corresponding stream id should match.
- sp<IBinder> binder = IInterface::asBinder(bufferProducers[0]);
- ssize_t index = mStreamMap.indexOfKey(binder);
+ SurfaceKey surfaceKey;
+ status_t ret = getSurfaceKey(surfaces[0], &surfaceKey);
+ if(ret != OK) {
+ ALOGE("%s: Camera %s: Could not get the SurfaceKey", __FUNCTION__, mCameraIdStr.c_str());
+ return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, "Could not get the SurfaceKey");
+ }
+ ssize_t index = mStreamMap.indexOfKey(surfaceKey);
if (index == NAME_NOT_FOUND) {
ALOGE("%s: Outputconfiguration is invalid", __FUNCTION__);
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
"OutputConfiguration is invalid");
}
- if (mStreamMap.valueFor(binder).streamId() != streamId) {
+ if (mStreamMap.valueFor(surfaceKey).streamId() != streamId) {
ALOGE("%s: Stream Id: %d provided doesn't match the id: %d in the stream map",
- __FUNCTION__, streamId, mStreamMap.valueFor(binder).streamId());
+ __FUNCTION__, streamId, mStreamMap.valueFor(surfaceKey).streamId());
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
"Stream id is invalid");
}
std::vector<size_t> removedSurfaceIds;
- std::vector<sp<IBinder>> removedOutputs;
+ std::vector<SurfaceKey> removedOutputs;
std::vector<SurfaceHolder> newOutputs;
std::vector<OutputStreamInfo> streamInfos;
- KeyedVector<sp<IBinder>, sp<IGraphicBufferProducer>> newOutputsMap;
- for (auto &it : bufferProducers) {
- newOutputsMap.add(IInterface::asBinder(it), it);
+ KeyedVector<SurfaceKey, ParcelableSurfaceType> newOutputsMap;
+ for (auto& surface : surfaces) {
+ SurfaceKey surfaceKey;
+ status_t ret = getSurfaceKey(surface, &surfaceKey);
+ if(ret != OK) {
+ ALOGE("%s: Camera %s: Could not get the SurfaceKey", __FUNCTION__,
+ mCameraIdStr.c_str());
+ return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION,
+ "Could not get the SurfaceKey");
+ }
+ newOutputsMap.add(surfaceKey, surface);
}
for (size_t i = 0; i < mStreamMap.size(); i++) {
@@ -1318,17 +1408,24 @@
for (size_t i = 0; i < newOutputsMap.size(); i++) {
OutputStreamInfo outInfo;
- sp<Surface> surface;
+ sp<Surface> outSurface;
int mirrorMode = outputConfiguration.getMirrorMode(newOutputsMap.valueAt(i));
- res = SessionConfigurationUtils::createSurfaceFromGbp(outInfo,
- /*isStreamInfoValid*/ false, surface, newOutputsMap.valueAt(i), mCameraIdStr,
- mDevice->infoPhysical(physicalCameraId), sensorPixelModesUsed, dynamicRangeProfile,
- streamUseCase, timestampBase, mirrorMode, colorSpace, /*respectSurfaceSize*/false);
- if (!res.isOk())
- return res;
+ res = SessionConfigurationUtils::createSurfaceFromGbp(
+ outInfo,
+ /*isStreamInfoValid*/ false, outSurface,
+ newOutputsMap
+ .valueAt(i)
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+ .graphicBufferProducer
+#endif
+ ,
+ mCameraIdStr, mDevice->infoPhysical(physicalCameraId), sensorPixelModesUsed,
+ dynamicRangeProfile, streamUseCase, timestampBase, mirrorMode, colorSpace,
+ /*respectSurfaceSize*/ false);
+ if (!res.isOk()) return res;
streamInfos.push_back(outInfo);
- newOutputs.push_back({surface, mirrorMode});
+ newOutputs.push_back({outSurface, mirrorMode});
}
//Trivial case no changes required
@@ -1337,8 +1434,7 @@
}
KeyedVector<sp<Surface>, size_t> outputMap;
- auto ret = mDevice->updateStream(streamId, newOutputs, streamInfos, removedSurfaceIds,
- &outputMap);
+ ret = mDevice->updateStream(streamId, newOutputs, streamInfos, removedSurfaceIds, &outputMap);
if (ret != OK) {
switch (ret) {
case NAME_NOT_FOUND:
@@ -1360,8 +1456,15 @@
}
for (size_t i = 0; i < outputMap.size(); i++) {
- mStreamMap.add(IInterface::asBinder(outputMap.keyAt(i)->getIGraphicBufferProducer()),
- StreamSurfaceId(streamId, outputMap.valueAt(i)));
+ SurfaceKey surfaceKey;
+ status_t ret = getSurfaceKey(outputMap.keyAt(i), &surfaceKey);
+ if(ret != OK) {
+ ALOGE("%s: Camera %s: Could not get the SurfaceKey", __FUNCTION__,
+ mCameraIdStr.c_str());
+ return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION,
+ "Could not get the SurfaceKey");
+ }
+ mStreamMap.add(surfaceKey, StreamSurfaceId(streamId, outputMap.valueAt(i)));
}
mConfiguredOutputs.replaceValueFor(streamId, outputConfiguration);
@@ -1641,12 +1744,11 @@
"OutputConfiguration isn't valid!");
}
- const std::vector<sp<IGraphicBufferProducer> >& bufferProducers =
- outputConfiguration.getGraphicBufferProducers();
- const std::string &physicalId = outputConfiguration.getPhysicalCameraId();
+ const std::vector<ParcelableSurfaceType>& surfaces = outputConfiguration.getSurfaces();
+ const std::string& physicalId = outputConfiguration.getPhysicalCameraId();
- if (bufferProducers.size() == 0) {
- ALOGE("%s: bufferProducers must not be empty", __FUNCTION__);
+ if (surfaces.size() == 0) {
+ ALOGE("%s: surfaces must not be empty", __FUNCTION__);
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, "Target Surface is invalid");
}
@@ -1686,34 +1788,47 @@
}
std::vector<SurfaceHolder> consumerSurfaceHolders;
- const std::vector<int32_t> &sensorPixelModesUsed =
+ const std::vector<int32_t>& sensorPixelModesUsed =
outputConfiguration.getSensorPixelModesUsed();
int64_t dynamicRangeProfile = outputConfiguration.getDynamicRangeProfile();
int32_t colorSpace = outputConfiguration.getColorSpace();
int64_t streamUseCase = outputConfiguration.getStreamUseCase();
int timestampBase = outputConfiguration.getTimestampBase();
- for (auto& bufferProducer : bufferProducers) {
+
+ for (auto& surface : surfaces) {
// Don't create multiple streams for the same target surface
- ssize_t index = mStreamMap.indexOfKey(IInterface::asBinder(bufferProducer));
+ SurfaceKey surfaceKey;
+ status_t ret = getSurfaceKey(surface, &surfaceKey);
+ if(ret != OK) {
+ ALOGE("%s: Camera %s: Could not get the SurfaceKey", __FUNCTION__,
+ mCameraIdStr.c_str());
+ return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION,
+ "Could not get the SurfaceKey");
+ }
+ ssize_t index = mStreamMap.indexOfKey(surfaceKey);
if (index != NAME_NOT_FOUND) {
ALOGV("Camera %s: Surface already has a stream created "
- " for it (ID %zd)", mCameraIdStr.c_str(), index);
+ " for it (ID %zd)",
+ mCameraIdStr.c_str(), index);
continue;
}
- sp<Surface> surface;
- int mirrorMode = outputConfiguration.getMirrorMode(bufferProducer);
- res = SessionConfigurationUtils::createSurfaceFromGbp(mStreamInfoMap[streamId],
- true /*isStreamInfoValid*/, surface, bufferProducer, mCameraIdStr,
- mDevice->infoPhysical(physicalId), sensorPixelModesUsed, dynamicRangeProfile,
- streamUseCase, timestampBase, mirrorMode, colorSpace, /*respectSurfaceSize*/false);
+ sp<Surface> outSurface;
+ int mirrorMode = outputConfiguration.getMirrorMode(surface);
+ res = SessionConfigurationUtils::createSurfaceFromGbp(
+ mStreamInfoMap[streamId], true /*isStreamInfoValid*/, outSurface,
+ surface
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+ .graphicBufferProducer
+#endif
+ , mCameraIdStr, mDevice->infoPhysical(physicalId),
+ sensorPixelModesUsed, dynamicRangeProfile, streamUseCase, timestampBase, mirrorMode,
+ colorSpace, /*respectSurfaceSize*/ false);
- if (!res.isOk())
- return res;
+ if (!res.isOk()) return res;
- consumerSurfaceHolders.push_back({surface, mirrorMode});
+ consumerSurfaceHolders.push_back({outSurface, mirrorMode});
}
-
// Gracefully handle case where finalizeOutputConfigurations is called
// without any new surface.
if (consumerSurfaceHolders.size() == 0) {
@@ -1727,11 +1842,22 @@
err = mDevice->setConsumerSurfaces(streamId, consumerSurfaceHolders, &consumerSurfaceIds);
if (err == OK) {
for (size_t i = 0; i < consumerSurfaceHolders.size(); i++) {
- sp<IBinder> binder = IInterface::asBinder(
- consumerSurfaceHolders[i].mSurface->getIGraphicBufferProducer());
- ALOGV("%s: mStreamMap add binder %p streamId %d, surfaceId %d", __FUNCTION__,
- binder.get(), streamId, consumerSurfaceIds[i]);
- mStreamMap.add(binder, StreamSurfaceId(streamId, consumerSurfaceIds[i]));
+ SurfaceKey surfaceKey;
+ status_t ret = getSurfaceKey(consumerSurfaceHolders[i].mSurface, &surfaceKey);
+ if(ret != OK) {
+ ALOGE("%s: Camera %s: Could not get the SurfaceKey", __FUNCTION__,
+ mCameraIdStr.c_str());
+ return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION,
+ "Could not get the SurfaceKey");
+ }
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+ ALOGV("%s: mStreamMap add surface_key %lu streamId %d, surfaceId %d", __FUNCTION__,
+ surfaceKey, streamId, consumerSurfaceIds[i]);
+#else
+ ALOGV("%s: mStreamMap add surface_key %p streamId %d, surfaceId %d", __FUNCTION__,
+ surfaceKey.get(), streamId, consumerSurfaceIds[i]);
+#endif
+ mStreamMap.add(surfaceKey, StreamSurfaceId(streamId, consumerSurfaceIds[i]));
}
if (deferredStreamIndex != NAME_NOT_FOUND) {
mDeferredStreams.removeItemsAt(deferredStreamIndex);
@@ -1768,6 +1894,34 @@
return binder::Status::ok();
}
+status_t CameraDeviceClient::CreateMetadataQueue(
+ std::unique_ptr<MetadataQueue>* metadata_queue, uint32_t default_size_bytes) {
+ if (metadata_queue == nullptr) {
+ ALOGE("%s: metadata_queue is nullptr", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ int32_t size = default_size_bytes;
+
+ *metadata_queue =
+ std::make_unique<MetadataQueue>(static_cast<size_t>(size),
+ /*configureEventFlagWord*/ false);
+ if (!(*metadata_queue)->isValid()) {
+ ALOGE("%s: Creating metadata queue (size %d) failed.", __FUNCTION__, size);
+ return NO_INIT;
+ }
+
+ return OK;
+}
+
+binder::Status CameraDeviceClient::getCaptureResultMetadataQueue(
+ android::hardware::common::fmq::MQDescriptor<
+ int8_t, android::hardware::common::fmq::SynchronizedReadWrite>* aidl_return) {
+
+ *aidl_return = mResultMetadataQueue->dupeDesc();
+ return binder::Status::ok();
+}
+
binder::Status CameraDeviceClient::getGlobalAudioRestriction(/*out*/ int32_t* outMode) {
ATRACE_CALL();
binder::Status res;
@@ -1866,7 +2020,7 @@
std::vector<int32_t> offlineStreamIds;
offlineStreamIds.reserve(offlineOutputIds.size());
- KeyedVector<sp<IBinder>, sp<CompositeStream>> offlineCompositeStreamMap;
+ KeyedVector<SurfaceKey, sp<CompositeStream>> offlineCompositeStreamMap;
for (const auto& streamId : offlineOutputIds) {
ssize_t index = mConfiguredOutputs.indexOfKey(streamId);
if (index == NAME_NOT_FOUND) {
@@ -1885,24 +2039,37 @@
Mutex::Autolock l(mCompositeLock);
bool isCompositeStream = false;
- for (const auto& gbp : mConfiguredOutputs.valueAt(index).getGraphicBufferProducers()) {
- sp<Surface> s = new Surface(gbp, false /*controlledByApp*/);
+
+ for (const auto& surface : mConfiguredOutputs.valueAt(index).getSurfaces()) {
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+ sp<Surface> s = surface.toSurface();
+#else
+ sp<Surface> s = new Surface(surface, false /*controlledByApp*/);
+#endif
isCompositeStream = camera3::DepthCompositeStream::isDepthCompositeStream(s) ||
- camera3::HeicCompositeStream::isHeicCompositeStream(s) ||
- (camera3::JpegRCompositeStream::isJpegRCompositeStream(s) &&
- !mDevice->isCompositeJpegRDisabled());
+ camera3::HeicCompositeStream::isHeicCompositeStream(s) ||
+ (camera3::JpegRCompositeStream::isJpegRCompositeStream(s) &&
+ !mDevice->isCompositeJpegRDisabled());
if (isCompositeStream) {
- auto compositeIdx = mCompositeStreamMap.indexOfKey(IInterface::asBinder(gbp));
+ SurfaceKey surfaceKey;
+ status_t ret = getSurfaceKey(surface, &surfaceKey);
+ if(ret != OK) {
+ ALOGE("%s: Camera %s: Could not get the SurfaceKey", __FUNCTION__,
+ mCameraIdStr.c_str());
+ return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION,
+ "Could not get the SurfaceKey");
+ }
+ auto compositeIdx = mCompositeStreamMap.indexOfKey(surfaceKey);
if (compositeIdx == NAME_NOT_FOUND) {
ALOGE("%s: Unknown composite stream", __FUNCTION__);
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
- "Unknown composite stream");
+ "Unknown composite stream");
}
- mCompositeStreamMap.valueAt(compositeIdx)->insertCompositeStreamIds(
- &offlineStreamIds);
+ mCompositeStreamMap.valueAt(compositeIdx)
+ ->insertCompositeStreamIds(&offlineStreamIds);
offlineCompositeStreamMap.add(mCompositeStreamMap.keyAt(compositeIdx),
- mCompositeStreamMap.valueAt(compositeIdx));
+ mCompositeStreamMap.valueAt(compositeIdx));
break;
}
}
@@ -2190,16 +2357,76 @@
mCameraServiceProxyWrapper->logClose(mCameraIdStr, closeLatencyMs, hasDeviceError);
}
+size_t CameraDeviceClient::writeResultMetadataIntoResultQueue(
+ const CameraMetadata &resultMetadata) {
+ ATRACE_CALL();
+
+ const camera_metadata_t *resultMetadataP = resultMetadata.getAndLock();
+ size_t resultSize = get_camera_metadata_size(resultMetadataP);
+ if (mResultMetadataQueue != nullptr &&
+ mResultMetadataQueue->write(reinterpret_cast<const int8_t*>(resultMetadataP),
+ resultSize)) {
+ resultMetadata.unlock(resultMetadataP);
+ return resultSize;
+ }
+ resultMetadata.unlock(resultMetadataP);
+ ALOGE(" %s couldn't write metadata into result queue ", __FUNCTION__);
+ return 0;
+}
+
/** Device-related methods */
+std::vector<PhysicalCaptureResultInfo> CameraDeviceClient::convertToFMQ(
+ const std::vector<PhysicalCaptureResultInfo> &physicalResults) {
+ std::vector<PhysicalCaptureResultInfo> retVal;
+ ALOGVV("%s E", __FUNCTION__);
+ for (const auto &srcPhysicalResult : physicalResults) {
+ size_t fmqSize = 0;
+ if (!mIsVendorClient && flags::fmq_metadata()) {
+ fmqSize = writeResultMetadataIntoResultQueue(
+ srcPhysicalResult.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>());
+ }
+ ALOGVV("%s physical metadata write size is %d", __FUNCTION__, (int)fmqSize);
+ if (fmqSize != 0) {
+ retVal.emplace_back(srcPhysicalResult.mPhysicalCameraId, fmqSize);
+ } else {
+ // The flag was off / we're serving VNDK shim call or FMQ write failed.
+ retVal.emplace_back(srcPhysicalResult.mPhysicalCameraId,
+ srcPhysicalResult.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>());
+ }
+ }
+ ALOGVV("%s X", __FUNCTION__);
+ return retVal;
+}
+
void CameraDeviceClient::onResultAvailable(const CaptureResult& result) {
ATRACE_CALL();
- ALOGV("%s", __FUNCTION__);
+ ALOGVV("%s E", __FUNCTION__);
// Thread-safe. No lock necessary.
sp<hardware::camera2::ICameraDeviceCallbacks> remoteCb = mRemoteCallback;
if (remoteCb != NULL) {
- remoteCb->onResultReceived(result.mMetadata, result.mResultExtras,
- result.mPhysicalMetadatas);
+ // Write result metadata into metadataQueue
+ size_t fmqMetadataSize = 0;
+ // Vendor clients need to modify metadata and also this call is in process
+ // before going through FMQ to vendor clients. So don't use FMQ here.
+ if (!mIsVendorClient && flags::fmq_metadata()) {
+ fmqMetadataSize = writeResultMetadataIntoResultQueue(result.mMetadata);
+ }
+ hardware::camera2::impl::CameraMetadataNative resultMetadata;
+ CameraMetadataInfo resultInfo;
+ if (fmqMetadataSize == 0) {
+ // The flag was off / we're serving VNDK shim call or FMQ write failed.
+ resultMetadata = result.mMetadata;
+ resultInfo.set<CameraMetadataInfo::metadata>(resultMetadata);
+ } else {
+ resultInfo.set<CameraMetadataInfo::fmqSize>(fmqMetadataSize);
+ }
+
+ std::vector<PhysicalCaptureResultInfo> physicalMetadatas =
+ convertToFMQ(result.mPhysicalMetadatas);
+
+ remoteCb->onResultReceived(resultInfo, result.mResultExtras,
+ physicalMetadatas);
}
// Access to the composite stream map must be synchronized
@@ -2207,6 +2434,7 @@
for (size_t i = 0; i < mCompositeStreamMap.size(); i++) {
mCompositeStreamMap.valueAt(i)->onResultAvailable(result);
}
+ ALOGVV("%s X", __FUNCTION__);
}
binder::Status CameraDeviceClient::checkPidStatus(const char* checkLocation) {
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index a8cf451..4ad3c49 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -23,6 +23,9 @@
#include <camera/camera2/SessionConfiguration.h>
#include <camera/camera2/SubmitInfo.h>
#include <unordered_map>
+#include <gui/Flags.h> // remove with WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+
+#include <fmq/AidlMessageQueueCpp.h>
#include "CameraOfflineSessionClient.h"
#include "CameraService.h"
@@ -37,6 +40,12 @@
namespace android {
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+typedef uint64_t SurfaceKey;
+#else
+typedef sp<IBinder> SurfaceKey;
+#endif
+
struct CameraDeviceClientBase :
public CameraService::BasicClient,
public hardware::camera2::BnCameraDeviceUser
@@ -161,6 +170,11 @@
virtual binder::Status setCameraAudioRestriction(int32_t mode) override;
+ virtual binder::Status getCaptureResultMetadataQueue(
+ android::hardware::common::fmq::MQDescriptor<
+ int8_t, android::hardware::common::fmq::SynchronizedReadWrite>*
+ aidl_return) override;
+
virtual binder::Status getGlobalAudioRestriction(/*out*/int32_t* outMode) override;
virtual binder::Status switchToOffline(
@@ -182,7 +196,8 @@
const AttributionSourceState& clientAttribution, int callingPid,
bool clientPackageOverride, const std::string& cameraId, int cameraFacing,
int sensorOrientation, int servicePid, bool overrideForPerfClass,
- int rotationOverride, const std::string& originalCameraId, bool sharedMode);
+ int rotationOverride, const std::string& originalCameraId, bool sharedMode,
+ bool isVendorClient);
virtual ~CameraDeviceClient();
virtual status_t initialize(sp<CameraProviderManager> manager,
@@ -233,6 +248,10 @@
*/
protected:
/** FilteredListener implementation **/
+
+ size_t writeResultMetadataIntoResultQueue(const CameraMetadata &result);
+ std::vector<PhysicalCaptureResultInfo> convertToFMQ(
+ const std::vector<PhysicalCaptureResultInfo> &physicalResults);
virtual void onResultAvailable(const CaptureResult& result);
virtual void detachDevice();
@@ -244,6 +263,11 @@
const CameraMetadata &getStaticInfo(const std::string &cameraId);
private:
+ using MetadataQueue = AidlMessageQueueCpp<
+ int8_t, android::hardware::common::fmq::SynchronizedReadWrite>;
+ using CameraMetadataInfo = android::hardware::camera2::CameraMetadataInfo;
+ status_t CreateMetadataQueue(
+ std::unique_ptr<MetadataQueue>* metadata_queue, uint32_t default_size);
// StreamSurfaceId encapsulates streamId + surfaceId for a particular surface.
// streamId specifies the index of the stream the surface belongs to, and the
// surfaceId specifies the index of the surface within the stream. (one stream
@@ -293,12 +317,20 @@
int* newStreamId = NULL);
// Utility method to insert the surface into SurfaceMap
- binder::Status insertGbpLocked(const sp<IGraphicBufferProducer>& gbp,
+ binder::Status insertSurfaceLocked(const ParcelableSurfaceType& surface,
/*out*/SurfaceMap* surfaceMap, /*out*/Vector<int32_t>* streamIds,
/*out*/int32_t* currentStreamId);
+ // A ParcelableSurfaceType can be either a view::Surface or IGBP.
+ // We use this type of surface when we need to be able to have a parcelable data type.
+ // view::Surface has helper functions to make converting between a regular Surface and a
+ // view::Surface easy.
+ status_t getSurfaceKey(ParcelableSurfaceType surface, SurfaceKey* out) const;
+ // Surface only
+ status_t getSurfaceKey(sp<Surface> surface, SurfaceKey* out) const;
+
// IGraphicsBufferProducer binder -> Stream ID + Surface ID for output streams
- KeyedVector<sp<IBinder>, StreamSurfaceId> mStreamMap;
+ KeyedVector<SurfaceKey, StreamSurfaceId> mStreamMap;
// Stream ID -> OutputConfiguration. Used for looking up Surface by stream/surface index
KeyedVector<int32_t, hardware::camera2::params::OutputConfiguration> mConfiguredOutputs;
@@ -322,6 +354,9 @@
int32_t mRequestIdCounter;
+ // Metadata queue to write the result metadata to.
+ std::unique_ptr<MetadataQueue> mResultMetadataQueue;
+
std::vector<std::string> mPhysicalCameraIds;
// The list of output streams whose surfaces are deferred. We have to track them separately
@@ -340,7 +375,7 @@
// Synchronize access to 'mCompositeStreamMap'
Mutex mCompositeLock;
- KeyedVector<sp<IBinder>, sp<CompositeStream>> mCompositeStreamMap;
+ KeyedVector<SurfaceKey, sp<CompositeStream>> mCompositeStreamMap;
sp<CameraProviderManager> mProviderManager;
@@ -361,6 +396,8 @@
// This only exists in case of camera ID Remapping.
const std::string mOriginalCameraId;
+
+ bool mIsVendorClient = false;
};
}; // namespace android
diff --git a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
index 71fd3ba..1e73d79 100644
--- a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
@@ -299,7 +299,10 @@
ALOGV("%s", __FUNCTION__);
if (mRemoteCallback.get() != NULL) {
- mRemoteCallback->onResultReceived(result.mMetadata, result.mResultExtras,
+ using hardware::camera2::CameraMetadataInfo;
+ CameraMetadataInfo resultInfo;
+ resultInfo.set<CameraMetadataInfo::metadata>(result.mMetadata);
+ mRemoteCallback->onResultReceived(resultInfo, result.mResultExtras,
result.mPhysicalMetadatas);
}
diff --git a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
index 78a3055..3799ba3 100644
--- a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
+++ b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
@@ -30,6 +30,12 @@
using android::hardware::camera2::ICameraDeviceCallbacks;
using camera3::CompositeStream;
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+typedef uint64_t SurfaceKey;
+#else
+typedef sp<IBinder> SurfaceKey;
+#endif
+
// Client for offline session. Note that offline session client does not affect camera service's
// client arbitration logic. It is camera HAL's decision to decide whether a normal camera
// client is conflicting with existing offline client(s).
@@ -45,7 +51,7 @@
public:
CameraOfflineSessionClient(
const sp<CameraService>& cameraService, sp<CameraOfflineSessionBase> session,
- const KeyedVector<sp<IBinder>, sp<CompositeStream>>& offlineCompositeStreamMap,
+ const KeyedVector<SurfaceKey, sp<CompositeStream>>& offlineCompositeStreamMap,
const sp<ICameraDeviceCallbacks>& remoteCallback,
std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils,
const AttributionSourceState& clientAttribution, int callingPid,
@@ -135,7 +141,7 @@
sp<camera2::FrameProcessorBase> mFrameProcessor;
// Offline composite stream map, output surface -> composite stream
- KeyedVector<sp<IBinder>, sp<CompositeStream>> mCompositeStreamMap;
+ KeyedVector<SurfaceKey, sp<CompositeStream>> mCompositeStreamMap;
};
} // namespace android
diff --git a/services/camera/libcameraservice/common/FrameProcessorBase.cpp b/services/camera/libcameraservice/common/FrameProcessorBase.cpp
index 2322def..31dcce2 100644
--- a/services/camera/libcameraservice/common/FrameProcessorBase.cpp
+++ b/services/camera/libcameraservice/common/FrameProcessorBase.cpp
@@ -29,6 +29,8 @@
namespace android {
namespace camera2 {
+using CameraMetadataInfo = android::hardware::camera2::CameraMetadataInfo;
+
FrameProcessorBase::FrameProcessorBase(wp<FrameProducer> device) :
Thread(/*canCallJava*/false),
mDevice(device),
@@ -99,7 +101,7 @@
for (const auto& physicalFrame : mLastPhysicalFrames) {
lastPhysicalFrames.emplace(physicalFrame.mPhysicalCameraId,
- physicalFrame.mPhysicalCameraMetadata);
+ physicalFrame.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>());
}
}
lastFrame.dump(fd, /*verbosity*/2, /*indentation*/6);
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 9e89a19..d95242b 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -61,6 +61,7 @@
#include <com_android_window_flags.h>
#include "CameraService.h"
+#include "FwkOnlyMetadataTags.h"
#include "aidl/android/hardware/graphics/common/Dataspace.h"
#include "aidl/AidlUtils.h"
#include "device3/Camera3Device.h"
@@ -3797,18 +3798,12 @@
}
status_t Camera3Device::removeFwkOnlyKeys(CameraMetadata *request) {
- static const std::array<uint32_t, 5> kFwkOnlyKeys = {
- ANDROID_CONTROL_AF_REGIONS_SET,
- ANDROID_CONTROL_AE_REGIONS_SET,
- ANDROID_CONTROL_AWB_REGIONS_SET,
- ANDROID_SCALER_CROP_REGION_SET,
- ANDROID_CONTROL_ZOOM_METHOD};
if (request == nullptr) {
ALOGE("%s request metadata nullptr", __FUNCTION__);
return BAD_VALUE;
}
status_t res = OK;
- for (const auto &key : kFwkOnlyKeys) {
+ for (const auto &key : kFwkOnlyMetadataKeys) {
if (request->exists(key)) {
res = request->erase(key);
if (res != OK) {
@@ -3887,12 +3882,6 @@
it != captureRequest->mSettingsList.end(); it++) {
if (parent->mUHRCropAndMeteringRegionMappers.find(it->cameraId) ==
parent->mUHRCropAndMeteringRegionMappers.end()) {
- if (removeFwkOnlyKeys(&(it->metadata)) != OK) {
- SET_ERR("RequestThread: Unable to remove fwk-only keys from request"
- "%d: %s (%d)", halRequest->frame_number, strerror(-res),
- res);
- return INVALID_OPERATION;
- }
continue;
}
@@ -3907,12 +3896,6 @@
return INVALID_OPERATION;
}
captureRequest->mUHRCropAndMeteringRegionsUpdated = true;
- if (removeFwkOnlyKeys(&(it->metadata)) != OK) {
- SET_ERR("RequestThread: Unable to remove fwk-only keys from request"
- "%d: %s (%d)", halRequest->frame_number, strerror(-res),
- res);
- return INVALID_OPERATION;
- }
}
}
@@ -3986,7 +3969,13 @@
"%d: %s (%d)", halRequest->frame_number, strerror(-res), res);
return INVALID_OPERATION;
}
-
+ res = removeFwkOnlyKeys(&(it->metadata));
+ if (res != OK) {
+ SET_ERR("RequestThread: Unable to remove fwk-only keys from request"
+ "%d: %s (%d)", halRequest->frame_number, strerror(-res),
+ res);
+ return INVALID_OPERATION;
+ }
if (!parent->mSupportsExtensionKeys) {
res = filterExtensionKeys(&it->metadata);
if (res != OK) {
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
index 78f1698..7a53847 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
@@ -56,6 +56,7 @@
using namespace android::camera3;
using namespace android::camera3::SessionConfigurationUtils;
using namespace android::hardware::camera;
+using CameraMetadataInfo = android::hardware::camera2::CameraMetadataInfo;
namespace flags = com::android::internal::camera::flags;
namespace android {
@@ -231,11 +232,12 @@
// Update vendor tag id for physical metadata
for (auto& physicalMetadata : result->mPhysicalMetadatas) {
- camera_metadata_t *pmeta = const_cast<camera_metadata_t *>(
- physicalMetadata.mPhysicalCameraMetadata.getAndLock());
+ auto &metadata =
+ physicalMetadata.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>();
+ camera_metadata_t *pmeta = const_cast<camera_metadata_t *>(metadata.getAndLock());
set_camera_metadata_vendor_id(pmeta, states.vendorTagId);
correctMeteringRegions(pmeta);
- physicalMetadata.mPhysicalCameraMetadata.unlock(pmeta);
+ metadata.unlock(pmeta);
}
// Valid result, insert into queue
@@ -362,7 +364,8 @@
for (auto& physicalMetadata : captureResult.mPhysicalMetadatas) {
camera_metadata_entry timestamp =
- physicalMetadata.mPhysicalCameraMetadata.find(ANDROID_SENSOR_TIMESTAMP);
+ physicalMetadata.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>().
+ find(ANDROID_SENSOR_TIMESTAMP);
if (timestamp.count == 0) {
SET_ERR("No timestamp provided by HAL for physical camera %s frame %d!",
physicalMetadata.mPhysicalCameraId.c_str(), frameNumber);
@@ -385,9 +388,8 @@
// Fix up result metadata to account for zoom ratio availabilities between
// HAL and app.
bool zoomRatioIs1 = cameraIdsWithZoom.find(states.cameraId) == cameraIdsWithZoom.end();
- bool appUsesZoomRatio = !zoomRatioIs1 || useZoomRatio;
res = states.zoomRatioMappers[states.cameraId].updateCaptureResult(
- &captureResult.mMetadata, appUsesZoomRatio);
+ &captureResult.mMetadata, useZoomRatio, zoomRatioIs1);
if (res != OK) {
SET_ERR("Failed to update capture result zoom ratio metadata for frame %d: %s (%d)",
frameNumber, strerror(-res), res);
@@ -416,7 +418,8 @@
return;
}
for (auto& physicalMetadata : captureResult.mPhysicalMetadatas) {
- res = fixupManualFlashStrengthControlTags(physicalMetadata.mPhysicalCameraMetadata);
+ res = fixupManualFlashStrengthControlTags(physicalMetadata.mCameraMetadataInfo.
+ get<CameraMetadataInfo::metadata>());
if (res != OK) {
SET_ERR("Failed to set flash strength level defaults in physical result"
" metadata: %s (%d)", strerror(-res), res);
@@ -432,7 +435,8 @@
return;
}
for (auto& physicalMetadata : captureResult.mPhysicalMetadatas) {
- res = fixupAutoframingTags(physicalMetadata.mPhysicalCameraMetadata);
+ res = fixupAutoframingTags(physicalMetadata.mCameraMetadataInfo.
+ get<CameraMetadataInfo::metadata>());
if (res != OK) {
SET_ERR("Failed to set autoframing defaults in physical result metadata: %s (%d)",
strerror(-res), res);
@@ -445,7 +449,7 @@
auto mapper = states.distortionMappers.find(cameraId);
if (mapper != states.distortionMappers.end()) {
res = mapper->second.correctCaptureResult(
- &physicalMetadata.mPhysicalCameraMetadata);
+ &physicalMetadata.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>());
if (res != OK) {
SET_ERR("Unable to correct physical capture result metadata for frame %d: %s (%d)",
frameNumber, strerror(-res), res);
@@ -454,9 +458,11 @@
}
// Note: Physical camera continues to use SCALER_CROP_REGION to reflect
- // zoom levels.
+ // zoom levels. Model this by treating app-set ZOOM_RATIO as 1x.
res = states.zoomRatioMappers[cameraId].updateCaptureResult(
- &physicalMetadata.mPhysicalCameraMetadata, /*appUsesZoomRatio*/ false);
+ &physicalMetadata.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>(),
+ /*zoomMethodIsRatio*/false,
+ /*zoomRatioIs1*/true);
if (res != OK) {
SET_ERR("Failed to update camera %s's physical zoom ratio metadata for "
"frame %d: %s(%d)", cameraId.c_str(), frameNumber, strerror(-res), res);
@@ -474,7 +480,7 @@
const std::string &cameraId = physicalMetadata.mPhysicalCameraId;
res = fixupMonochromeTags(states,
states.physicalDeviceInfoMap.at(cameraId),
- physicalMetadata.mPhysicalCameraMetadata);
+ physicalMetadata.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>());
if (res != OK) {
SET_ERR("Failed to override result metadata: %s (%d)", strerror(-res), res);
return;
@@ -484,7 +490,7 @@
std::unordered_map<std::string, CameraMetadata> monitoredPhysicalMetadata;
for (auto& m : physicalMetadatas) {
monitoredPhysicalMetadata.emplace(m.mPhysicalCameraId,
- CameraMetadata(m.mPhysicalCameraMetadata));
+ CameraMetadata(m.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>()));
}
states.tagMonitor.monitorMetadata(TagMonitor::RESULT,
frameNumber, sensorTimestamp, captureResult.mMetadata,
diff --git a/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp b/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp
index 5260ad3..ef2109a 100644
--- a/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp
+++ b/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp
@@ -290,7 +290,8 @@
return res;
}
-status_t ZoomRatioMapper::updateCaptureResult(CameraMetadata* result, bool useZoomRatio) {
+status_t ZoomRatioMapper::updateCaptureResult(
+ CameraMetadata* result, bool zoomMethodIsRatio, bool zoomRatioIs1) {
if (!mIsValid) return INVALID_OPERATION;
status_t res = OK;
@@ -300,6 +301,8 @@
if (res != OK) {
return res;
}
+
+ bool useZoomRatio = !zoomRatioIs1 || zoomMethodIsRatio;
if (mHalSupportsZoomRatio && !useZoomRatio) {
res = combineZoomAndCropLocked(result, true/*isResult*/, arrayWidth, arrayHeight);
} else if (!mHalSupportsZoomRatio && useZoomRatio) {
@@ -312,6 +315,12 @@
}
}
+ if (flags::zoom_method()) {
+ uint8_t zoomMethod = zoomMethodIsRatio ? ANDROID_CONTROL_ZOOM_METHOD_ZOOM_RATIO :
+ ANDROID_CONTROL_ZOOM_METHOD_AUTO;
+ result->update(ANDROID_CONTROL_ZOOM_METHOD, &zoomMethod, 1);
+ }
+
return res;
}
diff --git a/services/camera/libcameraservice/device3/ZoomRatioMapper.h b/services/camera/libcameraservice/device3/ZoomRatioMapper.h
index 0ac2e09..2ae2010 100644
--- a/services/camera/libcameraservice/device3/ZoomRatioMapper.h
+++ b/services/camera/libcameraservice/device3/ZoomRatioMapper.h
@@ -64,7 +64,9 @@
/**
* Update capture result to handle both cropRegion and zoomRatio.
*/
- status_t updateCaptureResult(CameraMetadata *request, bool useZoomRatio);
+ status_t updateCaptureResult(CameraMetadata *request,
+ bool zoomMethodIsRatio,
+ bool zoomRatioIs1);
public: // Visible for testing. Do not use concurently.
void scaleCoordinates(int32_t* coordPairs, int coordCount,
diff --git a/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.cpp b/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.cpp
index de51ffa..24d9a7e 100644
--- a/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.cpp
+++ b/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.cpp
@@ -167,11 +167,19 @@
}
binder::Status H2BCameraDeviceCallbacks::onResultReceived(
- const CameraMetadataNative& result,
+ const CameraMetadataInfo &resultInfo,
const CaptureResultExtras& resultExtras,
const ::std::vector<PhysicalCaptureResultInfo>& physicalCaptureResultInfos) {
// Wrap CameraMetadata, resultExtras and physicalCaptureResultInfos in on
// sp<RefBase>-able structure and post it.
+ // We modify metadata - since we want to filter out tags based on the vndk
+ // version, and also this communication is an in process function call.
+ // So we don't use FMQ for the shim layer. FMQ is still used for VNDK IPC.
+ if (resultInfo.getTag() != CameraMetadataInfo::metadata) {
+ ALOGE("Vendor callbacks got metadata in fmq ? ");
+ return binder::Status::ok();
+ }
+ const CameraMetadataNative &result = resultInfo.get<CameraMetadataInfo::metadata>();
sp<ResultWrapper> resultWrapper = new ResultWrapper(const_cast<CameraMetadataNative &>(result),
resultExtras, physicalCaptureResultInfos);
sp<AMessage> msg = new AMessage(kWhatResultReceived, mHandler);
diff --git a/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.h b/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.h
index 98a0dbb..e36c2ea 100644
--- a/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.h
+++ b/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.h
@@ -54,6 +54,7 @@
using hardware::kSynchronizedReadWrite;
using hardware::MessageQueue;
using CaptureResultMetadataQueue = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+using CameraMetadataInfo = android::hardware::camera2::CameraMetadataInfo;
struct H2BCameraDeviceCallbacks :
public H2BConverter<HCameraDeviceCallback, ICameraDeviceCallbacks, BnCameraDeviceCallbacks> {
@@ -72,7 +73,8 @@
int64_t timestamp) override;
virtual binder::Status onResultReceived(
- const CameraMetadataNative& result, const CaptureResultExtras& resultExtras,
+ const CameraMetadataInfo &,
+ const CaptureResultExtras& resultExtras,
const std::vector<PhysicalCaptureResultInfo>& physicalCaptureResultInfos) override;
virtual binder::Status onPrepared(int32_t streamId) override;
diff --git a/services/camera/libcameraservice/hidl/HidlCameraService.cpp b/services/camera/libcameraservice/hidl/HidlCameraService.cpp
index 9d140f2..9e66236 100644
--- a/services/camera/libcameraservice/hidl/HidlCameraService.cpp
+++ b/services/camera/libcameraservice/hidl/HidlCameraService.cpp
@@ -132,7 +132,7 @@
kDefaultDeviceId);
clientAttribution.packageName = "";
clientAttribution.attributionTag = std::nullopt;
- binder::Status serviceRet = mAidlICameraService->connectDevice(
+ binder::Status serviceRet = mAidlICameraService->connectDeviceVendor(
callbacks, cameraId, 0/*oomScoreOffset*/,
/*targetSdkVersion*/__ANDROID_API_FUTURE__, ROTATION_OVERRIDE_NONE,
clientAttribution, /*devicePolicy*/0, /*sharedMode*/false, /*out*/&deviceRemote);
diff --git a/services/camera/libcameraservice/hidl/Utils.cpp b/services/camera/libcameraservice/hidl/Utils.cpp
index d0302d0..786087d 100644
--- a/services/camera/libcameraservice/hidl/Utils.cpp
+++ b/services/camera/libcameraservice/hidl/Utils.cpp
@@ -14,11 +14,12 @@
* limitations under the License.
*/
-#include <hidl/Utils.h>
-#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
-#include <cutils/native_handle.h>
-#include <mediautils/AImageReaderUtils.h>
#include <camera/StringUtils.h>
+#include <cutils/native_handle.h>
+#include <gui/Flags.h> // remove with WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
+#include <hidl/Utils.h>
+#include <mediautils/AImageReaderUtils.h>
namespace android {
namespace hardware {
@@ -28,6 +29,7 @@
using hardware::graphics::bufferqueue::V1_0::utils::H2BGraphicBufferProducer;
using aimg::AImageReader_getHGBPFromHandle;
+using CameraMetadataInfo = android::hardware::camera2::CameraMetadataInfo;
// Note: existing data in dst will be gone. Caller still owns the memory of src
void convertToHidl(const camera_metadata_t *src, HCameraMetadata* dst) {
@@ -84,9 +86,9 @@
hardware::camera2::params::OutputConfiguration convertFromHidl(
const HOutputConfiguration &hOutputConfiguration) {
- std::vector<sp<IGraphicBufferProducer>> iGBPs;
- auto &windowHandles = hOutputConfiguration.windowHandles;
- iGBPs.reserve(windowHandles.size());
+ std::vector<ParcelableSurfaceType> surfaces;
+ auto& windowHandles = hOutputConfiguration.windowHandles;
+ surfaces.reserve(windowHandles.size());
for (auto &handle : windowHandles) {
auto igbp = AImageReader_getHGBPFromHandle(handle);
if (igbp == nullptr) {
@@ -94,10 +96,16 @@
__FUNCTION__, handle.getNativeHandle());
continue;
}
- iGBPs.push_back(new H2BGraphicBufferProducer(igbp));
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+ view::Surface surface;
+ surface.graphicBufferProducer = new H2BGraphicBufferProducer(igbp);
+ surfaces.push_back(surface);
+#else
+ surfaces.push_back(new H2BGraphicBufferProducer(igbp));
+#endif
}
hardware::camera2::params::OutputConfiguration outputConfiguration(
- iGBPs, convertFromHidl(hOutputConfiguration.rotation),
+ surfaces, convertFromHidl(hOutputConfiguration.rotation),
hOutputConfiguration.physicalCameraId,
hOutputConfiguration.windowGroupId, OutputConfiguration::SURFACE_TYPE_UNKNOWN, 0, 0,
(windowHandles.size() > 1));
@@ -274,7 +282,8 @@
hPhysicalCaptureResultInfo.physicalCameraId =
toString8(physicalCaptureResultInfo.mPhysicalCameraId);
const camera_metadata_t *rawMetadata =
- physicalCaptureResultInfo.mPhysicalCameraMetadata.getAndLock();
+ physicalCaptureResultInfo.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>().
+ getAndLock();
// Try using fmq at first.
size_t metadata_size = get_camera_metadata_size(rawMetadata);
if ((metadata_size > 0) && (captureResultMetadataQueue->availableToWrite() > 0)) {
@@ -287,7 +296,8 @@
hPhysicalCaptureResultInfo.physicalCameraMetadata.metadata(std::move(metadata));
}
}
- physicalCaptureResultInfo.mPhysicalCameraMetadata.unlock(rawMetadata);
+ physicalCaptureResultInfo.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>().
+ unlock(rawMetadata);
return hPhysicalCaptureResultInfo;
}
diff --git a/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp b/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp
index 6c98837..8c7d39e 100644
--- a/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp
+++ b/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp
@@ -54,6 +54,7 @@
using ICameraService::ROTATION_OVERRIDE_NONE;
using ICameraService::ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT;
+using android::hardware::camera2::CameraMetadataInfo;
const int32_t kPreviewThreshold = 8;
const int32_t kNumRequestsTested = 8;
@@ -778,7 +779,7 @@
return binder::Status::ok();
}
- virtual binder::Status onResultReceived(const CameraMetadata& /*metadata*/,
+ virtual binder::Status onResultReceived(const CameraMetadataInfo& /*metadata*/,
const CaptureResultExtras& /*resultExtras*/,
const std::vector<PhysicalCaptureResultInfo>& /*physicalResultInfos*/) {
return binder::Status::ok();
diff --git a/services/camera/libcameraservice/tests/CameraPermissionsTest.cpp b/services/camera/libcameraservice/tests/CameraPermissionsTest.cpp
index ff58c4a..2f035e7 100644
--- a/services/camera/libcameraservice/tests/CameraPermissionsTest.cpp
+++ b/services/camera/libcameraservice/tests/CameraPermissionsTest.cpp
@@ -34,6 +34,7 @@
using namespace android;
using namespace android::hardware::camera;
+using android::hardware::camera2::CameraMetadataInfo;
// Empty service listener.
class TestCameraServiceListener : public hardware::BnCameraServiceListener {
@@ -107,7 +108,7 @@
return binder::Status::ok();
}
- virtual binder::Status onResultReceived(const CameraMetadata& /*metadata*/,
+ virtual binder::Status onResultReceived(const CameraMetadataInfo& /*metadata*/,
const CaptureResultExtras& /*resultExtras*/,
const std::vector<PhysicalCaptureResultInfo>& /*physicalResultInfos*/) {
return binder::Status::ok();
diff --git a/services/camera/libcameraservice/tests/ZoomRatioTest.cpp b/services/camera/libcameraservice/tests/ZoomRatioTest.cpp
index a531e10..f00d1e7 100644
--- a/services/camera/libcameraservice/tests/ZoomRatioTest.cpp
+++ b/services/camera/libcameraservice/tests/ZoomRatioTest.cpp
@@ -296,7 +296,8 @@
}
metadata.update(ANDROID_SCALER_CROP_REGION, test2xCropRegion[index], 4);
- res = mapper.updateCaptureResult(&metadata, false/*useZoomRatio*/);
+ res = mapper.updateCaptureResult(&metadata, false /*zoomMethodIsRatio*/,
+ true/*requestedZoomRatioIs1*/);
ASSERT_EQ(res, OK);
entry = metadata.find(ANDROID_SCALER_CROP_REGION);
ASSERT_EQ(entry.count, 4U);
@@ -340,7 +341,8 @@
entry = metadata.find(ANDROID_CONTROL_ZOOM_RATIO);
EXPECT_NEAR(entry.data.f[0], 2.0f, kMaxAllowedRatioError);
- res = mapper.updateCaptureResult(&metadata, false/*useZoomRatio*/);
+ res = mapper.updateCaptureResult(&metadata, false/*useZoomMethod*/,
+ true/*requestedZoomRatioIs1*/);
ASSERT_EQ(res, OK);
entry = metadata.find(ANDROID_CONTROL_ZOOM_RATIO);
EXPECT_NEAR(entry.data.f[0], 1.0f, kMaxAllowedRatioError);
@@ -364,7 +366,8 @@
entry = metadata.find(ANDROID_CONTROL_ZOOM_RATIO);
EXPECT_NEAR(entry.data.f[0], 1.0f, kMaxAllowedRatioError);
- res = mapper.updateCaptureResult(&metadata, false/*useZoomRatio*/);
+ res = mapper.updateCaptureResult(&metadata, false/*zoomMethodIsRatio*/,
+ true/*requestedZoomRatioIs1*/);
ASSERT_EQ(res, OK);
entry = metadata.find(ANDROID_SCALER_CROP_REGION);
ASSERT_EQ(entry.count, 4U);
@@ -452,7 +455,8 @@
entry = metadata.find(ANDROID_CONTROL_ZOOM_RATIO);
ASSERT_EQ(entry.data.f[0], zoomRatio);
- res = mapper.updateCaptureResult(&metadata, true/*useZoomRatio*/);
+ res = mapper.updateCaptureResult(&metadata, false/*zoomMethodIsRatio*/,
+ false/*requestedZoomRatioIs1*/);
ASSERT_EQ(res, OK);
entry = metadata.find(ANDROID_SCALER_CROP_REGION);
ASSERT_EQ(entry.count, 4U);
diff --git a/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.cpp b/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.cpp
index 80af140..85a5afc 100644
--- a/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.cpp
+++ b/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.cpp
@@ -58,6 +58,10 @@
return ret.str();
}
+static std::string getAppOpsMessage(const std::string& cameraId) {
+ return cameraId.empty() ? std::string() : std::string("start camera ") + cameraId;
+}
+
} // namespace
namespace android {
@@ -298,33 +302,37 @@
bool AttributionAndPermissionUtils::hasPermissionsForCamera(
const std::string& cameraId, const AttributionSourceState& attributionSource,
bool forDataDelivery, bool checkAutomotive) {
- return checkPermission(cameraId, sCameraPermission, attributionSource, std::string(),
- AppOpsManager::OP_NONE, forDataDelivery, /* startDataDelivery */ false,
- checkAutomotive) != PermissionChecker::PERMISSION_HARD_DENIED;
+ return checkPermission(cameraId, sCameraPermission, attributionSource,
+ getAppOpsMessage(cameraId), AppOpsManager::OP_NONE, forDataDelivery,
+ /* startDataDelivery */ false, checkAutomotive)
+ != PermissionChecker::PERMISSION_HARD_DENIED;
}
PermissionChecker::PermissionResult
AttributionAndPermissionUtils::checkPermissionsForCameraForPreflight(
const std::string& cameraId, const AttributionSourceState& attributionSource) {
- return checkPermission(cameraId, sCameraPermission, attributionSource, std::string(),
- AppOpsManager::OP_NONE, /* forDataDelivery */ false,
- /* startDataDelivery */ false, /* checkAutomotive */ false);
+ return checkPermission(cameraId, sCameraPermission, attributionSource,
+ getAppOpsMessage(cameraId), AppOpsManager::OP_NONE,
+ /* forDataDelivery */ false, /* startDataDelivery */ false,
+ /* checkAutomotive */ false);
}
PermissionChecker::PermissionResult
AttributionAndPermissionUtils::checkPermissionsForCameraForDataDelivery(
const std::string& cameraId, const AttributionSourceState& attributionSource) {
- return checkPermission(cameraId, sCameraPermission, attributionSource, std::string(),
- AppOpsManager::OP_NONE, /* forDataDelivery */ true,
- /* startDataDelivery */ false, /* checkAutomotive */ false);
+ return checkPermission(cameraId, sCameraPermission, attributionSource,
+ getAppOpsMessage(cameraId), AppOpsManager::OP_NONE,
+ /* forDataDelivery */ true, /* startDataDelivery */ false,
+ /* checkAutomotive */ false);
}
PermissionChecker::PermissionResult
AttributionAndPermissionUtils::checkPermissionsForCameraForStartDataDelivery(
const std::string& cameraId, const AttributionSourceState& attributionSource) {
- return checkPermission(cameraId, sCameraPermission, attributionSource, std::string(),
- AppOpsManager::OP_NONE, /* forDataDelivery */ true,
- /* startDataDelivery */ true, /* checkAutomotive */ false);
+ return checkPermission(cameraId, sCameraPermission, attributionSource,
+ getAppOpsMessage(cameraId), AppOpsManager::OP_NONE,
+ /* forDataDelivery */ true, /* startDataDelivery */ true,
+ /* checkAutomotive */ false);
}
bool AttributionAndPermissionUtils::hasPermissionsForSystemCamera(
diff --git a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp
index 85bca6f..8f93ee0 100644
--- a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp
+++ b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp
@@ -18,13 +18,14 @@
#define ATRACE_TAG ATRACE_TAG_CAMERA
//#define LOG_NDEBUG 0
+#include <binder/IServiceManager.h>
+#include <camera/StringUtils.h>
+#include <gui/Flags.h> // remove with WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
#include <gui/Surface.h>
#include <inttypes.h>
+#include <system/window.h>
#include <utils/Log.h>
#include <utils/String16.h>
-#include <camera/StringUtils.h>
-#include <binder/IServiceManager.h>
-#include <system/window.h>
#include "aidl/android/hardware/graphics/common/Dataspace.h"
@@ -265,16 +266,24 @@
}
// Check 4K
- const auto& gbps = config.getGraphicBufferProducers();
+ const std::vector<ParcelableSurfaceType>& surfaces = config.getSurfaces();
int32_t width = 0, height = 0;
- if (gbps.size() > 0) {
- if (gbps[0] == nullptr) {
+ if (surfaces.size() > 0) {
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+ if (surfaces[0].isEmpty()) {
+#else
+ if (surfaces[0] == nullptr) {
+#endif
ALOGE("%s: Failed to query size due to abandoned surface.",
__FUNCTION__);
return CameraFeatureCombinationStats::CAMERA_FEATURE_UNKNOWN;
}
- sp<Surface> surface = new Surface(gbps[0], /*useAsync*/false);
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+ sp<Surface> surface = surfaces[0].toSurface();
+#else
+ sp<Surface> surface = new Surface(surfaces[0], /*useAsync*/false);
+#endif
ANativeWindow *anw = surface.get();
width = ANativeWindow_getWidth(anw);
diff --git a/services/camera/libcameraservice/utils/ClientManager.h b/services/camera/libcameraservice/utils/ClientManager.h
index b2b8685..0f0dc4c 100644
--- a/services/camera/libcameraservice/utils/ClientManager.h
+++ b/services/camera/libcameraservice/utils/ClientManager.h
@@ -746,9 +746,9 @@
for (auto it = mClients.begin(); it != mClients.end();)
{
if ((*it)->getKey() == key) {
- it = mClients.erase(it);
if (mListener != nullptr) mListener->onClientRemoved(**it);
clients.push_back(*it);
+ it = mClients.erase(it);
} else {
++it;
}
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
index ee4df4e..fd877ed 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
@@ -18,21 +18,23 @@
#include "SessionConfigurationUtils.h"
#include <android/data_space.h>
+#include <camera/StringUtils.h>
+#include <gui/Flags.h> // remove with WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+#include <ui/PublicFormat.h>
+#include "../CameraService.h"
#include "../api2/DepthCompositeStream.h"
#include "../api2/HeicCompositeStream.h"
+#include "SessionConfigurationUtils.h"
#include "aidl/android/hardware/graphics/common/Dataspace.h"
#include "api2/JpegRCompositeStream.h"
#include "binder/Status.h"
#include "common/CameraDeviceBase.h"
#include "common/HalConversionsTemplated.h"
-#include "../CameraService.h"
-#include "device3/aidl/AidlCamera3Device.h"
-#include "device3/hidl/HidlCamera3Device.h"
#include "device3/Camera3OutputStream.h"
#include "device3/ZoomRatioMapper.h"
+#include "device3/aidl/AidlCamera3Device.h"
+#include "device3/hidl/HidlCamera3Device.h"
#include "system/graphics-base-v1.1.h"
-#include <camera/StringUtils.h>
-#include <ui/PublicFormat.h>
using android::camera3::OutputStreamInfo;
using android::camera3::OutputStreamInfo;
@@ -827,8 +829,7 @@
}
for (const auto &it : outputConfigs) {
- const std::vector<sp<IGraphicBufferProducer>>& bufferProducers =
- it.getGraphicBufferProducers();
+ const std::vector<ParcelableSurfaceType>& surfaces = it.getSurfaces();
bool deferredConsumer = it.isDeferred();
bool isConfigurationComplete = it.isComplete();
const std::string &physicalCameraId = it.getPhysicalCameraId();
@@ -841,12 +842,12 @@
const CameraMetadata &metadataChosen =
physicalCameraId.size() > 0 ? physicalDeviceInfo : deviceInfo;
- size_t numBufferProducers = bufferProducers.size();
+ size_t numSurfaces = surfaces.size();
bool isStreamInfoValid = false;
int32_t groupId = it.isMultiResolution() ? it.getSurfaceSetID() : -1;
OutputStreamInfo streamInfo;
- res = checkSurfaceType(numBufferProducers, deferredConsumer, it.getSurfaceType(),
+ res = checkSurfaceType(numSurfaces, deferredConsumer, it.getSurfaceType(),
isConfigurationComplete);
if (!res.isOk()) {
return res;
@@ -861,7 +862,7 @@
int timestampBase = it.getTimestampBase();
// If the configuration is a deferred consumer, or a not yet completed
// configuration with no buffer producers attached.
- if (deferredConsumer || (!isConfigurationComplete && numBufferProducers == 0)) {
+ if (deferredConsumer || (!isConfigurationComplete && numSurfaces == 0)) {
streamInfo.width = it.getWidth();
streamInfo.height = it.getHeight();
auto surfaceType = it.getSurfaceType();
@@ -912,26 +913,31 @@
isStreamInfoValid = true;
- if (numBufferProducers == 0) {
+ if (numSurfaces == 0) {
continue;
}
}
- for (auto& bufferProducer : bufferProducers) {
- int mirrorMode = it.getMirrorMode(bufferProducer);
+ for (auto& surface_type : surfaces) {
sp<Surface> surface;
- res = createSurfaceFromGbp(streamInfo, isStreamInfoValid, surface, bufferProducer,
- logicalCameraId, metadataChosen, sensorPixelModesUsed, dynamicRangeProfile,
- streamUseCase, timestampBase, mirrorMode, colorSpace,
- /*respectSurfaceSize*/true);
+ int mirrorMode = it.getMirrorMode(surface_type);
+ res = createSurfaceFromGbp(streamInfo, isStreamInfoValid, surface,
+ surface_type
+#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES
+ .graphicBufferProducer
+#endif
+ , logicalCameraId,
+ metadataChosen, sensorPixelModesUsed, dynamicRangeProfile,
+ streamUseCase, timestampBase, mirrorMode, colorSpace,
+ /*respectSurfaceSize*/ true);
- if (!res.isOk())
- return res;
+ if (!res.isOk()) return res;
if (!isStreamInfoValid) {
- auto status = mapStream(streamInfo, isCompositeJpegRDisabled, deviceInfo,
- static_cast<camera_stream_rotation_t> (it.getRotation()), &streamIdx,
- physicalCameraId, groupId, logicalCameraId, streamConfiguration, earlyExit);
+ auto status = mapStream(streamInfo, isCompositeJpegRDisabled, deviceInfo,
+ static_cast<camera_stream_rotation_t>(it.getRotation()),
+ &streamIdx, physicalCameraId, groupId, logicalCameraId,
+ streamConfiguration, earlyExit);
if (*earlyExit || !status.isOk()) {
return status;
}
@@ -1253,14 +1259,6 @@
request->update(ANDROID_CONTROL_AUTOFRAMING, &kDefaultAutoframingMode, 1);
}
- if (flags::ae_priority()) {
- // Fill in CONTROL_AE_PRIORITY_MODE if not available
- if (!request->exists(ANDROID_CONTROL_AE_PRIORITY_MODE)) {
- static const uint8_t kDefaultAePriorityMode = ANDROID_CONTROL_AE_PRIORITY_MODE_OFF;
- request->update(ANDROID_CONTROL_AE_PRIORITY_MODE, &kDefaultAePriorityMode, 1);
- }
- }
-
return OK;
}
diff --git a/services/camera/virtualcamera/VirtualCameraRenderThread.cc b/services/camera/virtualcamera/VirtualCameraRenderThread.cc
index 58c6549..4c243e3 100644
--- a/services/camera/virtualcamera/VirtualCameraRenderThread.cc
+++ b/services/camera/virtualcamera/VirtualCameraRenderThread.cc
@@ -223,21 +223,6 @@
static_cast<uint64_t>(1e9 / VirtualCameraDevice::kMinFps));
}
-class FrameAvailableListenerProxy : public ConsumerBase::FrameAvailableListener {
- public:
- FrameAvailableListenerProxy(std::function<void()> callback)
- : mOnFrameAvailableCallback(callback) {
- }
-
- virtual void onFrameAvailable(const BufferItem&) override {
- ALOGV("%s: onFrameAvailable", __func__);
- mOnFrameAvailableCallback();
- }
-
- private:
- std::function<void()> mOnFrameAvailableCallback;
-};
-
} // namespace
CaptureRequestBuffer::CaptureRequestBuffer(int streamId, int bufferId,
@@ -383,10 +368,8 @@
EglTextureProgram::TextureFormat::RGBA);
mEglSurfaceTexture = std::make_unique<EglSurfaceTexture>(
mInputSurfaceSize.width, mInputSurfaceSize.height);
- sp<FrameAvailableListenerProxy> frameAvailableListener =
- sp<FrameAvailableListenerProxy>::make(
- [this]() { requestTextureUpdate(); });
- mEglSurfaceTexture->setFrameAvailableListener(frameAvailableListener);
+ mEglSurfaceTexture->setFrameAvailableListener(
+ [this]() { requestTextureUpdate(); });
mInputSurfacePromise.set_value(mEglSurfaceTexture->getSurface());
diff --git a/services/camera/virtualcamera/VirtualCameraSession.cc b/services/camera/virtualcamera/VirtualCameraSession.cc
index 88929cc..a5921af 100644
--- a/services/camera/virtualcamera/VirtualCameraSession.cc
+++ b/services/camera/virtualcamera/VirtualCameraSession.cc
@@ -189,7 +189,11 @@
}
halStream.overrideDataSpace = stream.dataSpace;
- halStream.producerUsage = BufferUsage::GPU_RENDER_TARGET;
+ halStream.producerUsage = static_cast<BufferUsage>(
+ static_cast<int64_t>(stream.usage) |
+ static_cast<int64_t>(BufferUsage::CAMERA_OUTPUT) |
+ static_cast<int64_t>(BufferUsage::GPU_RENDER_TARGET));
+
halStream.supportOffline = false;
return halStream;
}
diff --git a/services/camera/virtualcamera/util/EglSurfaceTexture.cc b/services/camera/virtualcamera/util/EglSurfaceTexture.cc
index fc469a0..f99b965 100644
--- a/services/camera/virtualcamera/util/EglSurfaceTexture.cc
+++ b/services/camera/virtualcamera/util/EglSurfaceTexture.cc
@@ -40,6 +40,21 @@
// Maximal number of buffers producer can dequeue without blocking.
constexpr int kBufferProducerMaxDequeueBufferCount = 64;
+class FrameAvailableListenerProxy : public ConsumerBase::FrameAvailableListener {
+ public:
+ FrameAvailableListenerProxy(const std::function<void()>& callback)
+ : mOnFrameAvailableCallback(callback) {
+ }
+
+ virtual void onFrameAvailable(const BufferItem&) override {
+ ALOGV("%s: onFrameAvailable", __func__);
+ mOnFrameAvailableCallback();
+ }
+
+ private:
+ std::function<void()> mOnFrameAvailableCallback;
+};
+
} // namespace
EglSurfaceTexture::EglSurfaceTexture(const uint32_t width, const uint32_t height)
@@ -92,8 +107,13 @@
}
void EglSurfaceTexture::setFrameAvailableListener(
- const wp<ConsumerBase::FrameAvailableListener>& listener) {
- mGlConsumer->setFrameAvailableListener(listener);
+ const std::function<void()>& listener) {
+ mFrameAvailableListener =
+ sp<FrameAvailableListenerProxy>::make([this, listener]() {
+ mIsFirstFrameDrawn.store(true);
+ listener();
+ });
+ mGlConsumer->setFrameAvailableListener(mFrameAvailableListener);
}
bool EglSurfaceTexture::waitForNextFrame(const std::chrono::nanoseconds timeout) {
@@ -106,7 +126,7 @@
}
bool EglSurfaceTexture::isFirstFrameDrawn() {
- return mGlConsumer->getFrameNumber() > 0;
+ return mIsFirstFrameDrawn.load();
}
GLuint EglSurfaceTexture::updateTexture() {
diff --git a/services/camera/virtualcamera/util/EglSurfaceTexture.h b/services/camera/virtualcamera/util/EglSurfaceTexture.h
index 9f75315..8b4d45e 100644
--- a/services/camera/virtualcamera/util/EglSurfaceTexture.h
+++ b/services/camera/virtualcamera/util/EglSurfaceTexture.h
@@ -62,8 +62,7 @@
// Returns false on timeout, true if new frame was received before timeout.
bool waitForNextFrame(std::chrono::nanoseconds timeout);
- void setFrameAvailableListener(
- const wp<ConsumerBase::FrameAvailableListener>& listener);
+ void setFrameAvailableListener(const std::function<void()>& listener);
// Update the texture with the most recent submitted buffer.
// Most be called on thread with EGL context.
@@ -99,6 +98,8 @@
GLuint mTextureId;
const uint32_t mWidth;
const uint32_t mHeight;
+ std::atomic_bool mIsFirstFrameDrawn = false;
+ sp<ConsumerBase::FrameAvailableListener> mFrameAvailableListener;
};
} // namespace virtualcamera
diff --git a/services/oboeservice/AAudioServiceEndpoint.cpp b/services/oboeservice/AAudioServiceEndpoint.cpp
index c677619..5375934 100644
--- a/services/oboeservice/AAudioServiceEndpoint.cpp
+++ b/services/oboeservice/AAudioServiceEndpoint.cpp
@@ -196,14 +196,14 @@
? AAudioConvert_inputPresetToAudioSource(params->getInputPreset())
: AUDIO_SOURCE_DEFAULT;
audio_flags_mask_t flags;
- std::optional<std::string> optTags = {};
+ std::string tags;
if (direction == AAUDIO_DIRECTION_OUTPUT) {
flags = AAudio_computeAudioFlagsMask(
params->getAllowedCapturePolicy(),
params->getSpatializationBehavior(),
params->isContentSpatialized(),
AUDIO_OUTPUT_FLAG_FAST);
- optTags = params->getTags();
+ tags = params->getTagsAsString();
} else {
flags = static_cast<audio_flags_mask_t>(AUDIO_FLAG_LOW_LATENCY
| AAudioConvert_privacySensitiveToAudioFlagsMask(params->isPrivacySensitive()));
@@ -215,9 +215,9 @@
.flags = flags,
.tags = ""
};
- if (optTags.has_value() && !optTags->empty()) {
- strncpy(nativeAttributes.tags, optTags.value().c_str(), AAUDIO_ATTRIBUTES_TAGS_MAX_SIZE);
- nativeAttributes.tags[AAUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1] = '\0';
+ if (!tags.empty()) {
+ strncpy(nativeAttributes.tags, tags.c_str(), AUDIO_ATTRIBUTES_TAGS_MAX_SIZE);
+ nativeAttributes.tags[AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1] = '\0';
}
return nativeAttributes;
}
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
index 66918c1..6c31d2c 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -150,15 +150,9 @@
// Try other formats if the config from APM is the same as our current config.
// Some HALs may report its format support incorrectly.
- if (previousConfig.format == config.format) {
- if (previousConfig.sample_rate == config.sample_rate) {
- config.format = getNextFormatToTry(config.format);
- } else if (!com::android::media::aaudio::sample_rate_conversion()) {
- ALOGI("%s() - AAudio SRC feature not enabled, different rates! %d != %d",
- __func__, previousConfig.sample_rate, config.sample_rate);
- result = AAUDIO_ERROR_INVALID_RATE;
- break;
- }
+ if ((previousConfig.format == config.format) &&
+ (previousConfig.sample_rate == config.sample_rate)) {
+ config.format = getNextFormatToTry(config.format);
}
ALOGD("%s() %#x %d failed, perhaps due to format or sample rate. Try again with %#x %d",
diff --git a/services/oboeservice/AAudioServiceEndpointShared.cpp b/services/oboeservice/AAudioServiceEndpointShared.cpp
index f54de5e..37ccf8a 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.cpp
+++ b/services/oboeservice/AAudioServiceEndpointShared.cpp
@@ -75,6 +75,9 @@
builder.setBufferCapacity(DEFAULT_BUFFER_CAPACITY);
+ // Each shared stream will use its own SRC.
+ builder.setSampleRate(AAUDIO_UNSPECIFIED);
+
result = mStreamInternal->open(builder);
setSampleRate(mStreamInternal->getSampleRate());
diff --git a/services/oboeservice/AAudioServiceStreamShared.cpp b/services/oboeservice/AAudioServiceStreamShared.cpp
index 04fcd6d..bd58fa2 100644
--- a/services/oboeservice/AAudioServiceStreamShared.cpp
+++ b/services/oboeservice/AAudioServiceStreamShared.cpp
@@ -144,6 +144,9 @@
goto error;
}
+ // Use the sample rate of the endpoint as each shared stream should use its own SRC.
+ setSampleRate(endpoint->getSampleRate());
+
// Is the request compatible with the shared endpoint?
setFormat(configurationInput.getFormat());
if (getFormat() == AUDIO_FORMAT_DEFAULT) {
@@ -154,16 +157,6 @@
goto error;
}
- setSampleRate(configurationInput.getSampleRate());
- if (getSampleRate() == AAUDIO_UNSPECIFIED) {
- setSampleRate(endpoint->getSampleRate());
- } else if (getSampleRate() != endpoint->getSampleRate()) {
- ALOGD("%s() mSampleRate = %d, need %d",
- __func__, getSampleRate(), endpoint->getSampleRate());
- result = AAUDIO_ERROR_INVALID_RATE;
- goto error;
- }
-
setChannelMask(configurationInput.getChannelMask());
if (getChannelMask() == AAUDIO_UNSPECIFIED) {
setChannelMask(endpoint->getChannelMask());