Merge "Transcoder: Don't preserve profile/level when switching codec." into sc-dev
diff --git a/MainlineFiles.cfg b/MainlineFiles.cfg
index f694a41..490bbbf 100644
--- a/MainlineFiles.cfg
+++ b/MainlineFiles.cfg
@@ -1,10 +1,13 @@
-#
+#
# mainline files for frameworks/av
+# this list used by tools/mainline_hook_*.sh to help separate
+# mainline changes vs framework changes, which release at different paces.
+#
#
# ignore comment (#) lines and blank lines
# rest are path prefixes starting at root of the project
# (so OWNERS, not frameworks/av/OWNERS)
-#
+#
# path
# INCLUDE path
# EXCLUDE path
@@ -24,4 +27,5 @@
media/codec2/components/
media/codecs/
media/extractors/
-media/libstagefright/mpeg2ts
+media/libstagefright/mpeg2ts/
+media/libstagefright/flac/
diff --git a/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl b/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
index 28a57bd..8e1fcc0 100644
--- a/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
+++ b/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
@@ -119,10 +119,11 @@
* @param width Width of the input buffers
* @param height Height of the input buffers
* @param format Format of the input buffers. One of HAL_PIXEL_FORMAT_*.
+ * @param isMultiResolution Whether the input stream supports variable resolution image.
*
* @return new stream ID
*/
- int createInputStream(int width, int height, int format);
+ int createInputStream(int width, int height, int format, boolean isMultiResolution);
/**
* Get the surface of the input stream.
diff --git a/camera/camera2/OutputConfiguration.cpp b/camera/camera2/OutputConfiguration.cpp
index 4e9b27d..2f6bc30 100644
--- a/camera/camera2/OutputConfiguration.cpp
+++ b/camera/camera2/OutputConfiguration.cpp
@@ -68,6 +68,10 @@
return mPhysicalCameraId;
}
+bool OutputConfiguration::isMultiResolution() const {
+ return mIsMultiResolution;
+}
+
OutputConfiguration::OutputConfiguration() :
mRotation(INVALID_ROTATION),
mSurfaceSetID(INVALID_SET_ID),
@@ -75,7 +79,8 @@
mWidth(0),
mHeight(0),
mIsDeferred(false),
- mIsShared(false) {
+ mIsShared(false),
+ mIsMultiResolution(false) {
}
OutputConfiguration::OutputConfiguration(const android::Parcel& parcel) :
@@ -145,6 +150,12 @@
parcel->readString16(&mPhysicalCameraId);
+ int isMultiResolution = 0;
+ if ((err = parcel->readInt32(&isMultiResolution)) != OK) {
+ ALOGE("%s: Failed to read surface isMultiResolution flag from parcel", __FUNCTION__);
+ return err;
+ }
+
mRotation = rotation;
mSurfaceSetID = setID;
mSurfaceType = surfaceType;
@@ -152,6 +163,7 @@
mHeight = height;
mIsDeferred = isDeferred != 0;
mIsShared = isShared != 0;
+ mIsMultiResolution = isMultiResolution != 0;
for (auto& surface : surfaceShims) {
ALOGV("%s: OutputConfiguration: %p, name %s", __FUNCTION__,
surface.graphicBufferProducer.get(),
@@ -160,8 +172,8 @@
}
ALOGV("%s: OutputConfiguration: rotation = %d, setId = %d, surfaceType = %d,"
- " physicalCameraId = %s", __FUNCTION__, mRotation, mSurfaceSetID,
- mSurfaceType, String8(mPhysicalCameraId).string());
+ " physicalCameraId = %s, isMultiResolution = %d", __FUNCTION__, mRotation,
+ mSurfaceSetID, mSurfaceType, String8(mPhysicalCameraId).string(), mIsMultiResolution);
return err;
}
@@ -175,6 +187,7 @@
mIsDeferred = false;
mIsShared = isShared;
mPhysicalCameraId = physicalId;
+ mIsMultiResolution = false;
}
OutputConfiguration::OutputConfiguration(
@@ -183,7 +196,7 @@
int width, int height, bool isShared)
: mGbps(gbps), mRotation(rotation), mSurfaceSetID(surfaceSetID), mSurfaceType(surfaceType),
mWidth(width), mHeight(height), mIsDeferred(false), mIsShared(isShared),
- mPhysicalCameraId(physicalCameraId) { }
+ mPhysicalCameraId(physicalCameraId), mIsMultiResolution(false) { }
status_t OutputConfiguration::writeToParcel(android::Parcel* parcel) const {
@@ -224,6 +237,9 @@
err = parcel->writeString16(mPhysicalCameraId);
if (err != OK) return err;
+ err = parcel->writeInt32(mIsMultiResolution ? 1 : 0);
+ if (err != OK) return err;
+
return OK;
}
diff --git a/camera/camera2/SessionConfiguration.cpp b/camera/camera2/SessionConfiguration.cpp
index a431a33..7cf6087 100644
--- a/camera/camera2/SessionConfiguration.cpp
+++ b/camera/camera2/SessionConfiguration.cpp
@@ -55,6 +55,12 @@
return err;
}
+ bool inputIsMultiResolution = false;
+ if ((err = parcel->readBool(&inputIsMultiResolution)) != OK) {
+ ALOGE("%s: Failed to read input multi-resolution flag from parcel", __FUNCTION__);
+ return err;
+ }
+
std::vector<OutputConfiguration> outputStreams;
if ((err = parcel->readParcelableVector(&outputStreams)) != OK) {
ALOGE("%s: Failed to read output configurations from parcel", __FUNCTION__);
@@ -65,6 +71,7 @@
mInputWidth = inputWidth;
mInputHeight = inputHeight;
mInputFormat = inputFormat;
+ mInputIsMultiResolution = inputIsMultiResolution;
for (auto& stream : outputStreams) {
mOutputStreams.push_back(stream);
}
@@ -90,6 +97,9 @@
err = parcel->writeInt32(mInputFormat);
if (err != OK) return err;
+ err = parcel->writeBool(mInputIsMultiResolution);
+ if (err != OK) return err;
+
err = parcel->writeParcelableVector(mOutputStreams);
if (err != OK) return err;
diff --git a/camera/cameraserver/Android.bp b/camera/cameraserver/Android.bp
index 9398ec3..8ca8920 100644
--- a/camera/cameraserver/Android.bp
+++ b/camera/cameraserver/Android.bp
@@ -42,6 +42,7 @@
"android.hardware.camera.provider@2.4",
"android.hardware.camera.provider@2.5",
"android.hardware.camera.provider@2.6",
+ "android.hardware.camera.provider@2.7",
"android.hardware.camera.device@1.0",
"android.hardware.camera.device@3.2",
"android.hardware.camera.device@3.4",
diff --git a/camera/include/camera/camera2/OutputConfiguration.h b/camera/include/camera/camera2/OutputConfiguration.h
index 95c4f39..6009370 100644
--- a/camera/include/camera/camera2/OutputConfiguration.h
+++ b/camera/include/camera/camera2/OutputConfiguration.h
@@ -47,6 +47,8 @@
bool isDeferred() const;
bool isShared() const;
String16 getPhysicalCameraId() const;
+ bool isMultiResolution() const;
+
/**
* Keep impl up-to-date with OutputConfiguration.java in frameworks/base
*/
@@ -83,7 +85,8 @@
mIsDeferred == other.mIsDeferred &&
mIsShared == other.mIsShared &&
gbpsEqual(other) &&
- mPhysicalCameraId == other.mPhysicalCameraId );
+ mPhysicalCameraId == other.mPhysicalCameraId &&
+ mIsMultiResolution == other.mIsMultiResolution);
}
bool operator != (const OutputConfiguration& other) const {
return !(*this == other);
@@ -114,6 +117,9 @@
if (mPhysicalCameraId != other.mPhysicalCameraId) {
return mPhysicalCameraId < other.mPhysicalCameraId;
}
+ if (mIsMultiResolution != other.mIsMultiResolution) {
+ return mIsMultiResolution < other.mIsMultiResolution;
+ }
return gbpsLessThan(other);
}
bool operator > (const OutputConfiguration& other) const {
@@ -133,6 +139,7 @@
bool mIsDeferred;
bool mIsShared;
String16 mPhysicalCameraId;
+ bool mIsMultiResolution;
};
} // namespace params
} // namespace camera2
diff --git a/camera/include/camera/camera2/SessionConfiguration.h b/camera/include/camera/camera2/SessionConfiguration.h
index 64288ed..29913f6 100644
--- a/camera/include/camera/camera2/SessionConfiguration.h
+++ b/camera/include/camera/camera2/SessionConfiguration.h
@@ -38,6 +38,7 @@
int getInputHeight() const { return mInputHeight; }
int getInputFormat() const { return mInputFormat; }
int getOperatingMode() const { return mOperatingMode; }
+ bool inputIsMultiResolution() const { return mInputIsMultiResolution; }
virtual status_t writeToParcel(android::Parcel* parcel) const override;
virtual status_t readFromParcel(const android::Parcel* parcel) override;
@@ -61,7 +62,8 @@
mInputWidth == other.mInputWidth &&
mInputHeight == other.mInputHeight &&
mInputFormat == other.mInputFormat &&
- mOperatingMode == other.mOperatingMode);
+ mOperatingMode == other.mOperatingMode &&
+ mInputIsMultiResolution == other.mInputIsMultiResolution);
}
bool operator != (const SessionConfiguration& other) const {
@@ -83,6 +85,10 @@
return mInputFormat < other.mInputFormat;
}
+ if (mInputIsMultiResolution != other.mInputIsMultiResolution) {
+ return mInputIsMultiResolution < other.mInputIsMultiResolution;
+ }
+
if (mOperatingMode != other.mOperatingMode) {
return mOperatingMode < other.mOperatingMode;
}
@@ -104,6 +110,7 @@
std::vector<OutputConfiguration> mOutputStreams;
int mInputWidth, mInputHeight, mInputFormat, mOperatingMode;
+ bool mInputIsMultiResolution = false;
};
} // namespace params
} // namespace camera2
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index c1b2712..4e07c5c 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -3868,6 +3868,35 @@
*/
ACAMERA_SCALER_DEFAULT_SECURE_IMAGE_SIZE = // int32[2]
ACAMERA_SCALER_START + 18,
+ /**
+ * <p>The available multi-resolution stream configurations that this
+ * physical camera device supports
+ * (i.e. format, width, height, output/input stream).</p>
+ *
+ * <p>Type: int32[n*4] (acamera_metadata_enum_android_scaler_physical_camera_multi_resolution_stream_configurations_t)</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>This list contains a subset of the parent logical camera's multi-resolution stream
+ * configurations which belong to this physical camera, and it will advertise and will only
+ * advertise the maximum supported resolutions for a particular format.</p>
+ * <p>If this camera device isn't a physical camera device constituting a logical camera,
+ * but a standalone ULTRA_HIGH_RESOLUTION_SENSOR camera, this field represents the
+ * multi-resolution input/output stream configurations of default mode and max resolution
+ * modes. The sizes will be the maximum resolution of a particular format for default mode
+ * and max resolution mode.</p>
+ * <p>This field will only be advertised if the device is a physical camera of a
+ * logical multi-camera device or an ultra high resolution sensor camera. For a logical
+ * multi-camera, the camera API will derive the logical camera’s multi-resolution stream
+ * configurations from all physical cameras. For an ultra high resolution sensor camera, this
+ * is used directly as the camera’s multi-resolution stream configurations.</p>
+ */
+ ACAMERA_SCALER_PHYSICAL_CAMERA_MULTI_RESOLUTION_STREAM_CONFIGURATIONS =
+ // int32[n*4] (acamera_metadata_enum_android_scaler_physical_camera_multi_resolution_stream_configurations_t)
+ ACAMERA_SCALER_START + 19,
ACAMERA_SCALER_END,
/**
@@ -8475,6 +8504,16 @@
} acamera_metadata_enum_android_scaler_rotate_and_crop_t;
+// ACAMERA_SCALER_PHYSICAL_CAMERA_MULTI_RESOLUTION_STREAM_CONFIGURATIONS
+typedef enum acamera_metadata_enum_acamera_scaler_physical_camera_multi_resolution_stream_configurations {
+ ACAMERA_SCALER_PHYSICAL_CAMERA_MULTI_RESOLUTION_STREAM_CONFIGURATIONS_OUTPUT
+ = 0,
+
+ ACAMERA_SCALER_PHYSICAL_CAMERA_MULTI_RESOLUTION_STREAM_CONFIGURATIONS_INPUT
+ = 1,
+
+} acamera_metadata_enum_android_scaler_physical_camera_multi_resolution_stream_configurations_t;
+
// ACAMERA_SENSOR_REFERENCE_ILLUMINANT1
typedef enum acamera_metadata_enum_acamera_sensor_reference_illuminant1 {
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index ef4c568..03a8dc9 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -16,6 +16,9 @@
libstagefright_foundation libjpeg libui libgui libcutils liblog \
libhidlbase libdatasource libaudioclient \
android.hardware.media.omx@1.0 \
+ media_permission-aidl-cpp
+
+LOCAL_STATIC_LIBRARIES := media_permission-aidl-cpp
LOCAL_C_INCLUDES:= \
frameworks/av/media/libstagefright \
@@ -48,7 +51,8 @@
LOCAL_SHARED_LIBRARIES := \
libstagefright libmedia liblog libutils libbinder \
- libstagefright_foundation libdatasource libaudioclient
+ libstagefright_foundation libdatasource libaudioclient \
+ media_permission-aidl-cpp
LOCAL_C_INCLUDES:= \
frameworks/av/camera/include \
@@ -85,7 +89,8 @@
LOCAL_C_INCLUDES:= \
frameworks/av/media/libstagefright \
frameworks/native/include/media/openmax \
- frameworks/native/include/media/hardware
+ frameworks/native/include/media/hardware \
+ media_permission-aidl-cpp
LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
@@ -113,7 +118,8 @@
LOCAL_SHARED_LIBRARIES := \
libstagefright libmedia liblog libutils libbinder \
- libstagefright_foundation libaudioclient
+ libstagefright_foundation libaudioclient \
+ media_permission-aidl-cpp
LOCAL_C_INCLUDES:= \
frameworks/av/media/libstagefright \
diff --git a/cmds/stagefright/audioloop.cpp b/cmds/stagefright/audioloop.cpp
index 84a6d6b..c86a611 100644
--- a/cmds/stagefright/audioloop.cpp
+++ b/cmds/stagefright/audioloop.cpp
@@ -24,6 +24,7 @@
#include <utils/String16.h>
+#include <android/media/permission/Identity.h>
#include <binder/ProcessState.h>
#include <media/mediarecorder.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -38,6 +39,8 @@
using namespace android;
+using media::permission::Identity;
+
static void usage(const char* name)
{
fprintf(stderr, "Usage: %s [-d du.ration] [-m] [-w] [-N name] [<output-file>]\n", name);
@@ -110,9 +113,10 @@
audio_attributes_t attr = AUDIO_ATTRIBUTES_INITIALIZER;
attr.source = AUDIO_SOURCE_MIC;
+ // TODO b/182392769: use identity util
source = new AudioSource(
&attr,
- String16(),
+ Identity(),
sampleRate,
channels);
} else {
diff --git a/drm/libmediadrm/CryptoHal.cpp b/drm/libmediadrm/CryptoHal.cpp
index af17679..3257f71 100644
--- a/drm/libmediadrm/CryptoHal.cpp
+++ b/drm/libmediadrm/CryptoHal.cpp
@@ -343,6 +343,7 @@
Return<void> hResult;
+ mLock.unlock();
if (mPluginV1_2 != NULL) {
hResult = mPluginV1_2->decrypt_1_2(secure, toHidlArray16(keyId), toHidlArray16(iv),
hMode, hPattern, hSubSamples, hSource, offset, hDestination,
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index a84fd92..253a1fa 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -16,13 +16,9 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "DrmHal"
-#include <iomanip>
-
-#include <utils/Log.h>
-
-#include <android/binder_manager.h>
#include <aidl/android/media/BnResourceManagerClient.h>
+#include <android/binder_manager.h>
#include <android/hardware/drm/1.2/types.h>
#include <android/hidl/manager/1.2/IServiceManager.h>
#include <hidl/ServiceManagement.h>
@@ -40,7 +36,9 @@
#include <mediadrm/DrmSessionManager.h>
#include <mediadrm/IDrmMetricsConsumer.h>
#include <mediadrm/DrmUtils.h>
+#include <utils/Log.h>
+#include <iomanip>
#include <vector>
using drm::V1_0::KeyedVector;
@@ -319,8 +317,7 @@
closeOpenSessions();
Mutex::Autolock autoLock(mLock);
- reportPluginMetrics();
- reportFrameworkMetrics();
+ reportFrameworkMetrics(reportPluginMetrics());
setListener(NULL);
mInitCheck = NO_INIT;
@@ -340,7 +337,7 @@
}
std::vector<sp<IDrmFactory>> DrmHal::makeDrmFactories() {
- std::vector<sp<IDrmFactory>> factories(DrmUtils::MakeDrmFactories());
+ static std::vector<sp<IDrmFactory>> factories(DrmUtils::MakeDrmFactories());
if (factories.size() == 0) {
// must be in passthrough mode, load the default passthrough service
auto passthrough = IDrmFactory::getService();
@@ -364,7 +361,7 @@
Return<void> hResult = factory->createPlugin(uuid, appPackageName.string(),
[&](Status status, const sp<IDrmPlugin>& hPlugin) {
if (status != Status::OK) {
- DrmUtils::LOG2BE("Failed to make drm plugin: %d", status);
+ DrmUtils::LOG2BE(uuid, "Failed to make drm plugin: %d", status);
return;
}
plugin = hPlugin;
@@ -372,7 +369,8 @@
);
if (!hResult.isOk()) {
- DrmUtils::LOG2BE("createPlugin remote call failed");
+ DrmUtils::LOG2BE(uuid, "createPlugin remote call failed: %s",
+ hResult.description().c_str());
}
return plugin;
@@ -580,6 +578,7 @@
}
if (mPlugin == NULL) {
+ DrmUtils::LOG2BE(uuid, "No supported hal instance found");
mInitCheck = ERROR_UNSUPPORTED;
} else {
mInitCheck = OK;
@@ -1464,7 +1463,7 @@
return hResult.isOk() ? err : DEAD_OBJECT;
}
-void DrmHal::reportFrameworkMetrics() const
+std::string DrmHal::reportFrameworkMetrics(const std::string& pluginMetrics) const
{
mediametrics_handle_t item(mediametrics_create("mediadrm"));
mediametrics_setUid(item, mMetrics.GetAppUid());
@@ -1493,21 +1492,26 @@
if (!b64EncodedMetrics.empty()) {
mediametrics_setCString(item, "serialized_metrics", b64EncodedMetrics.c_str());
}
+ if (!pluginMetrics.empty()) {
+ mediametrics_setCString(item, "plugin_metrics", pluginMetrics.c_str());
+ }
if (!mediametrics_selfRecord(item)) {
ALOGE("Failed to self record framework metrics");
}
mediametrics_delete(item);
+ return serializedMetrics;
}
-void DrmHal::reportPluginMetrics() const
+std::string DrmHal::reportPluginMetrics() const
{
Vector<uint8_t> metricsVector;
String8 vendor;
String8 description;
+ std::string metricsString;
if (getPropertyStringInternal(String8("vendor"), vendor) == OK &&
getPropertyStringInternal(String8("description"), description) == OK &&
getPropertyByteArrayInternal(String8("metrics"), metricsVector) == OK) {
- std::string metricsString = toBase64StringNoPad(metricsVector.array(),
+ metricsString = toBase64StringNoPad(metricsVector.array(),
metricsVector.size());
status_t res = android::reportDrmPluginMetrics(metricsString, vendor,
description, mMetrics.GetAppUid());
@@ -1515,6 +1519,7 @@
ALOGE("Metrics were retrieved but could not be reported: %d", res);
}
}
+ return metricsString;
}
bool DrmHal::requiresSecureDecoder(const char *mime) const {
diff --git a/drm/libmediadrm/DrmUtils.cpp b/drm/libmediadrm/DrmUtils.cpp
index f7e6717..ed3848d 100644
--- a/drm/libmediadrm/DrmUtils.cpp
+++ b/drm/libmediadrm/DrmUtils.cpp
@@ -43,6 +43,9 @@
#include <mediadrm/ICrypto.h>
#include <mediadrm/IDrm.h>
+#include <map>
+#include <string>
+
using HServiceManager = ::android::hidl::manager::V1_2::IServiceManager;
using ::android::hardware::hidl_array;
using ::android::hardware::hidl_string;
@@ -66,8 +69,8 @@
return obj;
}
-template <typename Hal, typename V>
-void MakeHidlFactories(const uint8_t uuid[16], V &factories) {
+template <typename Hal, typename V, typename M>
+void MakeHidlFactories(const uint8_t uuid[16], V &factories, M& instances) {
sp<HServiceManager> serviceManager = HServiceManager::getService();
if (serviceManager == nullptr) {
LOG2BE("Failed to get service manager");
@@ -78,7 +81,7 @@
for (const auto &instance : registered) {
auto factory = Hal::getService(instance);
if (factory != nullptr) {
- LOG2BI("found %s %s", Hal::descriptor, instance.c_str());
+ instances[instance.c_str()] = Hal::descriptor;
if (!uuid || factory->isCryptoSchemeSupported(uuid)) {
factories.push_back(factory);
}
@@ -87,6 +90,12 @@
});
}
+template <typename Hal, typename V>
+void MakeHidlFactories(const uint8_t uuid[16], V &factories) {
+ std::map<std::string, std::string> instances;
+ MakeHidlFactories<Hal>(uuid, factories, instances);
+}
+
hidl_vec<uint8_t> toHidlVec(const void *ptr, size_t size) {
hidl_vec<uint8_t> vec(size);
if (ptr != nullptr) {
@@ -108,7 +117,7 @@
factory->createPlugin(toHidlArray16(uuid), hidl_string(appPackageName),
[&](::V1_0::Status status, const sp<::V1_0::IDrmPlugin> &hPlugin) {
if (status != ::V1_0::Status::OK) {
- LOG2BE("MakeDrmPlugin failed: %d", status);
+ LOG2BE(uuid, "MakeDrmPlugin failed: %d", status);
return;
}
plugin = hPlugin;
@@ -123,7 +132,7 @@
factory->createPlugin(toHidlArray16(uuid), toHidlVec(initData, initDataSize),
[&](::V1_0::Status status, const sp<::V1_0::ICryptoPlugin> &hPlugin) {
if (status != ::V1_0::Status::OK) {
- LOG2BE("MakeCryptoPlugin failed: %d", status);
+ LOG2BE(uuid, "MakeCryptoPlugin failed: %d", status);
return;
}
plugin = hPlugin;
@@ -147,11 +156,15 @@
std::vector<sp<::V1_0::IDrmFactory>> MakeDrmFactories(const uint8_t uuid[16]) {
std::vector<sp<::V1_0::IDrmFactory>> drmFactories;
- MakeHidlFactories<::V1_0::IDrmFactory>(uuid, drmFactories);
- MakeHidlFactories<::V1_1::IDrmFactory>(uuid, drmFactories);
- MakeHidlFactories<::V1_2::IDrmFactory>(uuid, drmFactories);
- MakeHidlFactories<::V1_3::IDrmFactory>(uuid, drmFactories);
- MakeHidlFactories<::V1_4::IDrmFactory>(uuid, drmFactories);
+ std::map<std::string, std::string> instances;
+ MakeHidlFactories<::V1_0::IDrmFactory>(uuid, drmFactories, instances);
+ MakeHidlFactories<::V1_1::IDrmFactory>(uuid, drmFactories, instances);
+ MakeHidlFactories<::V1_2::IDrmFactory>(uuid, drmFactories, instances);
+ MakeHidlFactories<::V1_3::IDrmFactory>(uuid, drmFactories, instances);
+ MakeHidlFactories<::V1_4::IDrmFactory>(uuid, drmFactories, instances);
+ for (auto const& entry : instances) {
+ LOG2BI("found instance=%s version=%s", entry.first.c_str(), entry.second.c_str());
+ }
return drmFactories;
}
@@ -255,6 +268,8 @@
return ERROR_DRM_PROVISIONING_CONFIG;
case ::V1_4::Status::PROVISIONING_PARSE_ERROR:
return ERROR_DRM_PROVISIONING_PARSE;
+ case ::V1_4::Status::PROVISIONING_REQUEST_REJECTED:
+ return ERROR_DRM_PROVISIONING_REQUEST_REJECTED;
case ::V1_4::Status::RETRYABLE_PROVISIONING_ERROR:
return ERROR_DRM_PROVISIONING_RETRY;
case ::V1_4::Status::SECURE_STOP_RELEASE_ERROR:
diff --git a/drm/libmediadrm/include/mediadrm/DrmHal.h b/drm/libmediadrm/include/mediadrm/DrmHal.h
index a0aac30..c5206fa 100644
--- a/drm/libmediadrm/include/mediadrm/DrmHal.h
+++ b/drm/libmediadrm/include/mediadrm/DrmHal.h
@@ -241,8 +241,8 @@
void writeByteArray(Parcel &obj, const hidl_vec<uint8_t>& array);
- void reportPluginMetrics() const;
- void reportFrameworkMetrics() const;
+ std::string reportPluginMetrics() const;
+ std::string reportFrameworkMetrics(const std::string& pluginMetrics) const;
status_t getPropertyStringInternal(String8 const &name, String8 &value) const;
status_t getPropertyByteArrayInternal(String8 const &name,
Vector<uint8_t> &value) const;
diff --git a/drm/libmediadrm/interface/mediadrm/DrmUtils.h b/drm/libmediadrm/interface/mediadrm/DrmUtils.h
index 7fe3501..988cda9 100644
--- a/drm/libmediadrm/interface/mediadrm/DrmUtils.h
+++ b/drm/libmediadrm/interface/mediadrm/DrmUtils.h
@@ -33,8 +33,10 @@
#include <cstdint>
#include <ctime>
#include <deque>
+#include <endian.h>
#include <iterator>
#include <mutex>
+#include <string>
#include <vector>
@@ -88,6 +90,14 @@
}
}
+template <typename... Args>
+void LogToBuffer(android_LogPriority level, const uint8_t uuid[16], const char *fmt, Args... args) {
+ const uint64_t* uuid2 = reinterpret_cast<const uint64_t*>(uuid);
+ std::string uuidFmt("uuid=[%lx %lx] ");
+ uuidFmt += fmt;
+ LogToBuffer(level, uuidFmt.c_str(), htobe64(uuid2[0]), htobe64(uuid2[1]), args...);
+}
+
#ifndef LOG2BE
#define LOG2BE(...) LogToBuffer(ANDROID_LOG_ERROR, __VA_ARGS__)
#define LOG2BW(...) LogToBuffer(ANDROID_LOG_WARN, __VA_ARGS__)
@@ -196,10 +206,13 @@
hResult = plugin->getLogMessages(cb);
}
if (!hResult.isOk()) {
- LOG2BW("%s::getLogMessages remote call failed", T::descriptor);
+ LOG2BW("%s::getLogMessages remote call failed %s",
+ T::descriptor, hResult.description().c_str());
}
auto allLogs(gLogBuf.getLogs());
+ LOG2BI("framework logs size %zu; plugin logs size %zu",
+ allLogs.size(), pluginLogs.size());
std::copy(pluginLogs.begin(), pluginLogs.end(), std::back_inserter(allLogs));
std::sort(allLogs.begin(), allLogs.end(),
[](const ::V1_4::LogMessage &a, const ::V1_4::LogMessage &b) {
diff --git a/drm/mediadrm/plugins/clearkey/default/JsonWebKey.cpp b/drm/mediadrm/plugins/clearkey/default/JsonWebKey.cpp
index 53ffae4..a2d506d 100644
--- a/drm/mediadrm/plugins/clearkey/default/JsonWebKey.cpp
+++ b/drm/mediadrm/plugins/clearkey/default/JsonWebKey.cpp
@@ -61,7 +61,7 @@
// all the base64 encoded keys. Each key is also stored separately as
// a JSON object in mJsonObjects[1..n] where n is the total
// number of keys in the set.
- if (!isJsonWebKeySet(mJsonObjects[0])) {
+ if (mJsonObjects.size() == 0 || !isJsonWebKeySet(mJsonObjects[0])) {
return false;
}
diff --git a/drm/mediadrm/plugins/clearkey/hidl/JsonWebKey.cpp b/drm/mediadrm/plugins/clearkey/hidl/JsonWebKey.cpp
index d93777d..99668a7 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/JsonWebKey.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/JsonWebKey.cpp
@@ -65,7 +65,7 @@
// all the base64 encoded keys. Each key is also stored separately as
// a JSON object in mJsonObjects[1..n] where n is the total
// number of keys in the set.
- if (!isJsonWebKeySet(mJsonObjects[0])) {
+ if (mJsonObjects.size() == 0 || !isJsonWebKeySet(mJsonObjects[0])) {
return false;
}
diff --git a/media/codec2/components/avc/C2SoftAvcEnc.cpp b/media/codec2/components/avc/C2SoftAvcEnc.cpp
index cfaeb66..43b2c14 100644
--- a/media/codec2/components/avc/C2SoftAvcEnc.cpp
+++ b/media/codec2/components/avc/C2SoftAvcEnc.cpp
@@ -186,6 +186,23 @@
.build());
addParameter(
+ DefineParam(mQuantization, C2_PARAMKEY_QUANTIZATION)
+ .withDefault(new C2StreamQuantizationInfo::output(0u,
+ DEFAULT_QP_MAX, DEFAULT_QP_MIN,
+ DEFAULT_QP_MAX, DEFAULT_QP_MIN,
+ DEFAULT_QP_MAX, DEFAULT_QP_MIN))
+ .withFields({
+ C2F(mQuantization, iMax).inRange(1, 51),
+ C2F(mQuantization, iMin).inRange(1, 51),
+ C2F(mQuantization, pMax).inRange(1, 51),
+ C2F(mQuantization, pMin).inRange(1, 51),
+ C2F(mQuantization, bMax).inRange(1, 51),
+ C2F(mQuantization, bMin).inRange(1, 51),
+ })
+ .withSetter(QuantizationSetter)
+ .build());
+
+ addParameter(
DefineParam(mRequestSync, C2_PARAMKEY_REQUEST_SYNC_FRAME)
.withDefault(new C2StreamRequestSyncFrameTuning::output(0u, C2_FALSE))
.withFields({C2F(mRequestSync, value).oneOf({ C2_FALSE, C2_TRUE }) })
@@ -220,6 +237,71 @@
return res;
}
+ static C2R QuantizationSetter(bool mayBlock, C2P<C2StreamQuantizationInfo::output> &me) {
+ (void)mayBlock;
+ (void)me;
+ C2R res = C2R::Ok();
+
+ ALOGV("QuantizationSetter enters max/min i %d/%d p %d/%d b %d/%d",
+ me.v.iMax, me.v.iMin, me.v.pMax, me.v.pMin, me.v.bMax, me.v.bMin);
+
+ // bounds checking
+ constexpr int qp_lowest = 1;
+ constexpr int qp_highest = 51;
+
+ if (me.v.iMax < qp_lowest) {
+ me.set().iMax = qp_lowest;
+ } else if (me.v.iMax > qp_highest) {
+ me.set().iMax = qp_highest;
+ }
+
+ if (me.v.iMin < qp_lowest) {
+ me.set().iMin = qp_lowest;
+ } else if (me.v.iMin > qp_highest) {
+ me.set().iMin = qp_highest;
+ }
+
+ if (me.v.pMax < qp_lowest) {
+ me.set().pMax = qp_lowest;
+ } else if (me.v.pMax > qp_highest) {
+ me.set().pMax = qp_highest;
+ }
+
+ if (me.v.pMin < qp_lowest) {
+ me.set().pMin = qp_lowest;
+ } else if (me.v.pMin > qp_highest) {
+ me.set().pMin = qp_highest;
+ }
+
+ if (me.v.bMax < qp_lowest) {
+ me.set().bMax = qp_lowest;
+ } else if (me.v.bMax > qp_highest) {
+ me.set().bMax = qp_highest;
+ }
+
+ if (me.v.bMin < qp_lowest) {
+ me.set().bMin = qp_lowest;
+ } else if (me.v.bMin > qp_highest) {
+ me.set().bMin = qp_highest;
+ }
+
+ // consistency checking, e.g. min<max
+ //
+ if (me.v.iMax < me.v.iMin) {
+ me.set().iMax = me.v.iMin;
+ }
+ if (me.v.pMax < me.v.pMin) {
+ me.set().pMax = me.v.pMin;
+ }
+ if (me.v.bMax < me.v.bMin) {
+ me.set().bMax = me.v.bMin;
+ }
+
+ // TODO: enforce any sort of i_max < p_max < b_max?
+
+ return res;
+ }
+
static C2R SizeSetter(bool mayBlock, const C2P<C2StreamPictureSizeInfo::input> &oldMe,
C2P<C2StreamPictureSizeInfo::input> &me) {
(void)mayBlock;
@@ -393,6 +475,7 @@
std::shared_ptr<C2StreamBitrateInfo::output> getBitrate_l() const { return mBitrate; }
std::shared_ptr<C2StreamRequestSyncFrameTuning::output> getRequestSync_l() const { return mRequestSync; }
std::shared_ptr<C2StreamGopTuning::output> getGop_l() const { return mGop; }
+ std::shared_ptr<C2StreamQuantizationInfo::output> getQuantization_l() const { return mQuantization; }
private:
std::shared_ptr<C2StreamUsageTuning::input> mUsage;
@@ -404,6 +487,7 @@
std::shared_ptr<C2StreamProfileLevelInfo::output> mProfileLevel;
std::shared_ptr<C2StreamSyncFrameIntervalTuning::output> mSyncFramePeriod;
std::shared_ptr<C2StreamGopTuning::output> mGop;
+ std::shared_ptr<C2StreamQuantizationInfo::output> mQuantization;
};
#define ive_api_function ih264e_api_function
@@ -664,6 +748,7 @@
ive_ctl_set_qp_op_t s_qp_op;
IV_STATUS_T status;
+ // set the defaults
s_qp_ip.e_cmd = IVE_CMD_VIDEO_CTL;
s_qp_ip.e_sub_cmd = IVE_CMD_CTL_SET_QP;
@@ -679,6 +764,21 @@
s_qp_ip.u4_b_qp_max = DEFAULT_QP_MAX;
s_qp_ip.u4_b_qp_min = DEFAULT_QP_MIN;
+ // parameter parsing ensured proper range 1..51, so only worry about ordering
+ bool valid = true;
+ if (mQuantization->iMax < mQuantization->iMin) valid = false;
+ if (mQuantization->pMax < mQuantization->pMin) valid = false;
+ if (mQuantization->bMax < mQuantization->bMin) valid = false;
+
+ if (valid) {
+ s_qp_ip.u4_i_qp_max = mQuantization->iMax;
+ s_qp_ip.u4_i_qp_min = mQuantization->iMin;
+ s_qp_ip.u4_p_qp_max = mQuantization->pMax;
+ s_qp_ip.u4_p_qp_min = mQuantization->pMin;
+ s_qp_ip.u4_b_qp_max = mQuantization->bMax;
+ s_qp_ip.u4_b_qp_min = mQuantization->bMin;
+ }
+
s_qp_ip.u4_timestamp_high = -1;
s_qp_ip.u4_timestamp_low = -1;
@@ -926,6 +1026,7 @@
mIInterval = mIntf->getSyncFramePeriod_l();
mIDRInterval = mIntf->getSyncFramePeriod_l();
gop = mIntf->getGop_l();
+ mQuantization = mIntf->getQuantization_l();
}
if (gop && gop->flexCount() > 0) {
uint32_t syncInterval = 1;
diff --git a/media/codec2/components/avc/C2SoftAvcEnc.h b/media/codec2/components/avc/C2SoftAvcEnc.h
index 555055b..e4bf0b0 100644
--- a/media/codec2/components/avc/C2SoftAvcEnc.h
+++ b/media/codec2/components/avc/C2SoftAvcEnc.h
@@ -192,6 +192,7 @@
std::shared_ptr<C2StreamFrameRateInfo::output> mFrameRate;
std::shared_ptr<C2StreamBitrateInfo::output> mBitrate;
std::shared_ptr<C2StreamRequestSyncFrameTuning::output> mRequestSync;
+ std::shared_ptr<C2StreamQuantizationInfo::output> mQuantization;
uint32_t mOutBufferSize;
UWORD32 mHeaderGenerated;
diff --git a/media/codec2/components/flac/Android.bp b/media/codec2/components/flac/Android.bp
index 1143bed..38dfce4 100644
--- a/media/codec2/components/flac/Android.bp
+++ b/media/codec2/components/flac/Android.bp
@@ -42,11 +42,8 @@
srcs: ["C2SoftFlacEnc.cpp"],
- shared_libs: [
- "libaudioutils",
- ],
-
static_libs: [
"libFLAC",
+ "libaudioutils",
],
}
diff --git a/media/codec2/components/mpeg4_h263/TEST_MAPPING b/media/codec2/components/mpeg4_h263/TEST_MAPPING
new file mode 100644
index 0000000..93fba22
--- /dev/null
+++ b/media/codec2/components/mpeg4_h263/TEST_MAPPING
@@ -0,0 +1,6 @@
+// mappings for frameworks/av/media/codec2/components/mpeg4_h263
+{
+ "presubmit": [
+ { "name": "C2SoftMpeg4DecTest" }
+ ]
+}
diff --git a/media/codec2/components/tests/Android.bp b/media/codec2/components/tests/Android.bp
new file mode 100644
index 0000000..3c68eee
--- /dev/null
+++ b/media/codec2/components/tests/Android.bp
@@ -0,0 +1,68 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_av_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_av_license"],
+}
+
+cc_defaults {
+ name: "C2SoftCodecTest-defaults",
+ gtest: true,
+ host_supported: false,
+ srcs: [
+ "C2SoftCodecTest.cpp",
+ ],
+
+ static_libs: [
+ "liblog",
+ "libion",
+ "libfmq",
+ "libbase",
+ "libutils",
+ "libcutils",
+ "libcodec2",
+ "libhidlbase",
+ "libdmabufheap",
+ "libcodec2_vndk",
+ "libnativewindow",
+ "libcodec2_soft_common",
+ "libsfplugin_ccodec_utils",
+ "libstagefright_foundation",
+ "libstagefright_bufferpool@2.0.1",
+ "android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@3.0",
+ "android.hardware.media.bufferpool@2.0",
+ "android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.allocator@3.0",
+ "android.hardware.graphics.bufferqueue@2.0",
+ ],
+
+ shared_libs: [
+ "libui",
+ "libdl",
+ "libhardware",
+ "libvndksupport",
+ "libprocessgroup",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+}
+
+cc_test {
+ name: "C2SoftMpeg4DecTest",
+ defaults: ["C2SoftCodecTest-defaults"],
+
+ static_libs: [
+ "libstagefright_m4vh263dec",
+ "libcodec2_soft_mpeg4dec",
+ ],
+
+ test_suites: [
+ "general-tests",
+ ],
+}
diff --git a/media/codec2/components/tests/C2SoftCodecTest.cpp b/media/codec2/components/tests/C2SoftCodecTest.cpp
new file mode 100644
index 0000000..84c2562
--- /dev/null
+++ b/media/codec2/components/tests/C2SoftCodecTest.cpp
@@ -0,0 +1,105 @@
+/******************************************************************************
+ *
+ * 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.
+ *
+ *****************************************************************************
+ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
+ */
+#include <C2Config.h>
+#include <C2ComponentFactory.h>
+#include <gtest/gtest.h>
+#include <log/log.h>
+
+using namespace android;
+extern "C" ::C2ComponentFactory* CreateCodec2Factory();
+extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory);
+
+class C2SoftCodecTest : public ::testing::Test {
+public:
+ void SetUp() override {
+ mFactory = CreateCodec2Factory();
+ }
+
+ void TearDown() override {
+ if (mFactory) {
+ DestroyCodec2Factory(mFactory);
+ }
+ }
+
+ c2_status_t createComponent(
+ std::shared_ptr<C2Component>* const comp) {
+ if (!mFactory) {
+ return C2_NO_INIT;
+ }
+ return mFactory->createComponent(
+ kPlaceholderId, comp, std::default_delete<C2Component>());
+ }
+
+ c2_status_t createInterface(
+ std::shared_ptr<C2ComponentInterface>* const intf) {
+ if (!mFactory) {
+ return C2_NO_INIT;
+ }
+ return mFactory->createInterface(
+ kPlaceholderId, intf, std::default_delete<C2ComponentInterface>());
+ }
+
+ ::C2ComponentFactory *getFactory() { return mFactory; }
+
+private:
+ static constexpr ::c2_node_id_t kPlaceholderId = 0;
+
+ ::C2ComponentFactory *mFactory;
+};
+
+TEST_F(C2SoftCodecTest, PictureSizeInfoTest) {
+ std::shared_ptr<C2ComponentInterface> interface;
+ c2_status_t status = createInterface(&interface);
+ ASSERT_EQ(status, C2_OK) << "Error in createInterface";
+ ASSERT_NE(interface, nullptr) << "interface is null";
+
+ std::unique_ptr<C2StreamPictureSizeInfo::output> param =
+ std::make_unique<C2StreamPictureSizeInfo::output>();
+ std::vector<C2FieldSupportedValuesQuery> validValueInfos = {
+ C2FieldSupportedValuesQuery::Current(
+ C2ParamField(param.get(), &C2StreamPictureSizeInfo::width)),
+ C2FieldSupportedValuesQuery::Current(
+ C2ParamField(param.get(), &C2StreamPictureSizeInfo::height))};
+ status = interface->querySupportedValues_vb(validValueInfos, C2_MAY_BLOCK);
+ ASSERT_EQ(status, C2_OK) << "Error in querySupportedValues_vb";
+ ASSERT_EQ(validValueInfos.size(), 2) << "querySupportedValues_vb didn't return 2 values";
+
+ ASSERT_EQ(validValueInfos[0].values.range.max.ref<uint32_t>(), 1920)
+ << "Incorrect maximum value for width";
+ ASSERT_EQ(validValueInfos[1].values.range.max.ref<uint32_t>(), 1920)
+ << "Incorrect maximum value for height";
+ ASSERT_EQ(validValueInfos[0].values.range.min.ref<uint32_t>(), 2)
+ << "Incorrect minimum value for width";
+ ASSERT_EQ(validValueInfos[1].values.range.min.ref<uint32_t>(), 2)
+ << "Incorrect minimum value for height";
+ ASSERT_EQ(validValueInfos[0].values.range.step.ref<uint32_t>(), 2)
+ << "Incorrect alignment value for width";
+ ASSERT_EQ(validValueInfos[1].values.range.step.ref<uint32_t>(), 2)
+ << "Incorrect alignment value for height";
+
+ return;
+}
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ ALOGV("Test result = %d\n", status);
+ return status;
+}
diff --git a/media/codec2/core/include/C2Config.h b/media/codec2/core/include/C2Config.h
index 752140a..8e8a08b 100644
--- a/media/codec2/core/include/C2Config.h
+++ b/media/codec2/core/include/C2Config.h
@@ -187,6 +187,8 @@
kParamIndexPictureType,
kParamIndexHdr10PlusMetadata,
+ kParamIndexQuantization,
+
/* ------------------------------------ video components ------------------------------------ */
kParamIndexFrameRate = C2_PARAM_INDEX_VIDEO_PARAM_START,
@@ -708,6 +710,38 @@
C2StreamProfileLevelInfo;
constexpr char C2_PARAMKEY_PROFILE_LEVEL[] = "coded.pl";
+struct C2QuantizationStruct {
+ int32_t iMax; ///< max/min for I frames
+ int32_t iMin;
+ int32_t pMax; ///< max/min for P frames
+ int32_t pMin;
+ int32_t bMax; ///< max/min for B frames
+ int32_t bMin;
+
+ C2QuantizationStruct(
+ int32_t iMax_ = INT32_MAX,
+ int32_t iMin_ = INT32_MIN,
+ int32_t pMax_ = INT32_MAX,
+ int32_t pMin_ = INT32_MIN,
+ int32_t bMax_ = INT32_MAX,
+ int32_t bMin_ = INT32_MIN)
+ : iMax(iMax_), iMin(iMin_),
+ pMax(pMax_), pMin(pMin_),
+ bMax(bMax_), bMin(bMin_) { }
+
+ DEFINE_AND_DESCRIBE_C2STRUCT(Quantization) // reference?
+ C2FIELD(iMax, "i-max")
+ C2FIELD(iMin, "i-min")
+ C2FIELD(pMax, "p-max")
+ C2FIELD(pMin, "p-min")
+ C2FIELD(bMax, "b-max")
+ C2FIELD(bMin, "b-min")
+};
+
+typedef C2StreamParam<C2Info, C2QuantizationStruct, kParamIndexQuantization>
+ C2StreamQuantizationInfo;
+constexpr char C2_PARAMKEY_QUANTIZATION[] = "coded.qp";
+
/**
* Codec-specific initialization data.
*
diff --git a/media/codec2/hidl/1.0/utils/InputSurfaceConnection.cpp b/media/codec2/hidl/1.0/utils/InputSurfaceConnection.cpp
index 5ec88ec..7c2e014 100644
--- a/media/codec2/hidl/1.0/utils/InputSurfaceConnection.cpp
+++ b/media/codec2/hidl/1.0/utils/InputSurfaceConnection.cpp
@@ -201,6 +201,8 @@
c2_status_t err = mAllocator->priorGraphicAllocation(handle, &alloc);
mAllocatorMutex.unlock();
if (err != OK) {
+ native_handle_close(handle);
+ native_handle_delete(handle);
return UNKNOWN_ERROR;
}
std::shared_ptr<C2GraphicBlock> block =
diff --git a/media/codec2/sfplugin/C2OMXNode.cpp b/media/codec2/sfplugin/C2OMXNode.cpp
index ab73245..466eedc 100644
--- a/media/codec2/sfplugin/C2OMXNode.cpp
+++ b/media/codec2/sfplugin/C2OMXNode.cpp
@@ -33,12 +33,14 @@
#include <OMX_IndexExt.h>
#include <android/fdsan.h>
+#include <media/stagefright/foundation/ColorUtils.h>
#include <media/stagefright/omx/OMXUtils.h>
#include <media/stagefright/MediaErrors.h>
#include <ui/Fence.h>
#include <ui/GraphicBuffer.h>
#include <utils/Thread.h>
+#include "utils/Codec2Mapper.h"
#include "C2OMXNode.h"
namespace android {
@@ -71,6 +73,25 @@
jobs->cond.broadcast();
}
+ void setDataspace(android_dataspace dataspace) {
+ Mutexed<Jobs>::Locked jobs(mJobs);
+ ColorUtils::convertDataSpaceToV0(dataspace);
+ jobs->configUpdate.emplace_back(new C2StreamDataSpaceInfo::input(0u, dataspace));
+ int32_t standard = (int32_t(dataspace) & HAL_DATASPACE_STANDARD_MASK)
+ >> HAL_DATASPACE_STANDARD_SHIFT;
+ int32_t transfer = (int32_t(dataspace) & HAL_DATASPACE_TRANSFER_MASK)
+ >> HAL_DATASPACE_TRANSFER_SHIFT;
+ int32_t range = (int32_t(dataspace) & HAL_DATASPACE_RANGE_MASK)
+ >> HAL_DATASPACE_RANGE_SHIFT;
+ std::unique_ptr<C2StreamColorAspectsInfo::input> colorAspects =
+ std::make_unique<C2StreamColorAspectsInfo::input>(0u);
+ if (C2Mapper::map(standard, &colorAspects->primaries, &colorAspects->matrix)
+ && C2Mapper::map(transfer, &colorAspects->transfer)
+ && C2Mapper::map(range, &colorAspects->range)) {
+ jobs->configUpdate.push_back(std::move(colorAspects));
+ }
+ }
+
protected:
bool threadLoop() override {
constexpr nsecs_t kIntervalNs = nsecs_t(10) * 1000 * 1000; // 10ms
@@ -102,6 +123,9 @@
uniqueFds.push_back(std::move(queue.workList.front().fd1));
queue.workList.pop_front();
}
+ for (const std::unique_ptr<C2Param> ¶m : jobs->configUpdate) {
+ items.front()->input.configUpdate.emplace_back(C2Param::Copy(*param));
+ }
jobs.unlock();
for (int fenceFd : fenceFds) {
@@ -119,6 +143,7 @@
queued = true;
}
if (queued) {
+ jobs->configUpdate.clear();
return true;
}
if (i == 0) {
@@ -161,6 +186,7 @@
std::map<std::weak_ptr<Codec2Client::Component>,
Queue,
std::owner_less<std::weak_ptr<Codec2Client::Component>>> queues;
+ std::vector<std::unique_ptr<C2Param>> configUpdate;
Condition cond;
};
Mutexed<Jobs> mJobs;
@@ -172,6 +198,9 @@
mQueueThread(new QueueThread) {
android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ALWAYS);
mQueueThread->run("C2OMXNode", PRIORITY_AUDIO);
+
+ Mutexed<android_dataspace>::Locked ds(mDataspace);
+ *ds = HAL_DATASPACE_UNKNOWN;
}
status_t C2OMXNode::freeNode() {
@@ -392,6 +421,8 @@
if (err != OK) {
(void)fd0.release();
(void)fd1.release();
+ native_handle_close(handle);
+ native_handle_delete(handle);
return UNKNOWN_ERROR;
}
block = _C2BlockFactory::CreateGraphicBlock(alloc);
@@ -459,8 +490,11 @@
android_dataspace dataSpace = (android_dataspace)msg.u.event_data.data1;
uint32_t pixelFormat = msg.u.event_data.data3;
- // TODO: set dataspace on component to see if it impacts color aspects
ALOGD("dataspace changed to %#x pixel format: %#x", dataSpace, pixelFormat);
+ mQueueThread->setDataspace(dataSpace);
+
+ Mutexed<android_dataspace>::Locked ds(mDataspace);
+ *ds = dataSpace;
return OK;
}
@@ -493,4 +527,8 @@
(void)mBufferSource->onInputBufferEmptied(bufferId, -1);
}
+android_dataspace C2OMXNode::getDataspace() {
+ return *mDataspace.lock();
+}
+
} // namespace android
diff --git a/media/codec2/sfplugin/C2OMXNode.h b/media/codec2/sfplugin/C2OMXNode.h
index 1717c96..5d587bc 100644
--- a/media/codec2/sfplugin/C2OMXNode.h
+++ b/media/codec2/sfplugin/C2OMXNode.h
@@ -93,6 +93,8 @@
*/
void onInputBufferDone(c2_cntr64_t index);
+ android_dataspace getDataspace();
+
private:
std::weak_ptr<Codec2Client::Component> mComp;
sp<IOMXBufferSource> mBufferSource;
@@ -101,6 +103,7 @@
uint32_t mWidth;
uint32_t mHeight;
uint64_t mUsage;
+ Mutexed<android_dataspace> mDataspace;
// WORKAROUND: timestamp adjustment
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 66a2b6a..fe451f6 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -44,6 +44,7 @@
#include <media/stagefright/BufferProducerWrapper.h>
#include <media/stagefright/MediaCodecConstants.h>
#include <media/stagefright/PersistentSurface.h>
+#include <utils/NativeHandle.h>
#include "C2OMXNode.h"
#include "CCodecBufferChannel.h"
@@ -210,8 +211,6 @@
(OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits,
&usage, sizeof(usage));
- // NOTE: we do not use/pass through color aspects from GraphicBufferSource as we
- // communicate that directly to the component.
mSource->configure(
mOmxNode, static_cast<hardware::graphics::common::V1_0::Dataspace>(mDataSpace));
return OK;
@@ -410,6 +409,10 @@
mNode->onInputBufferDone(index);
}
+ android_dataspace getDataspace() override {
+ return mNode->getDataspace();
+ }
+
private:
sp<HGraphicBufferSource> mSource;
sp<C2OMXNode> mNode;
@@ -552,13 +555,15 @@
}
// Report to MediaCodec
- // Note: for now we do not propagate the error code to MediaCodec as we would need
- // to translate to a MediaCodec error.
+ // Note: for now we do not propagate the error code to MediaCodec
+ // except for C2_NO_MEMORY, as we would need to translate to a MediaCodec error.
sp<CCodec> codec(mCodec.promote());
if (!codec || !codec->mCallback) {
return;
}
- codec->mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
+ codec->mCallback->onError(
+ errorCode == C2_NO_MEMORY ? NO_MEMORY : UNKNOWN_ERROR,
+ ACTION_CODE_FATAL);
}
virtual void onDeath(
@@ -794,10 +799,30 @@
mChannel->setMetaMode(CCodecBufferChannel::MODE_ANW);
}
+ status_t err = OK;
sp<RefBase> obj;
sp<Surface> surface;
if (msg->findObject("native-window", &obj)) {
surface = static_cast<Surface *>(obj.get());
+ // setup tunneled playback
+ if (surface != nullptr) {
+ Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
+ const std::unique_ptr<Config> &config = *configLocked;
+ if ((config->mDomain & Config::IS_DECODER)
+ && (config->mDomain & Config::IS_VIDEO)) {
+ int32_t tunneled;
+ if (msg->findInt32("feature-tunneled-playback", &tunneled) && tunneled != 0) {
+ ALOGI("Configuring TUNNELED video playback.");
+
+ err = configureTunneledVideoPlayback(comp, &config->mSidebandHandle, msg);
+ if (err != OK) {
+ ALOGE("configureTunneledVideoPlayback failed!");
+ return err;
+ }
+ config->mTunneled = true;
+ }
+ }
+ }
setSurface(surface);
}
@@ -1006,6 +1031,29 @@
}
}
+ // get color aspects
+ getColorAspectsFromFormat(msg, config->mClientColorAspects);
+
+ /*
+ * Handle dataspace
+ */
+ int32_t usingRecorder;
+ if (msg->findInt32("android._using-recorder", &usingRecorder) && usingRecorder) {
+ android_dataspace dataSpace = HAL_DATASPACE_BT709;
+ int32_t width, height;
+ if (msg->findInt32("width", &width)
+ && msg->findInt32("height", &height)) {
+ setDefaultCodecColorAspectsIfNeeded(config->mClientColorAspects, width, height);
+ // TODO: read dataspace / color aspect from the component
+ setColorAspectsIntoFormat(
+ config->mClientColorAspects, const_cast<sp<AMessage> &>(msg));
+ dataSpace = getDataSpaceForColorAspects(
+ config->mClientColorAspects, true /* mayexpand */);
+ }
+ msg->setInt32("android._dataspace", (int32_t)dataSpace);
+ ALOGD("setting dataspace to %x", dataSpace);
+ }
+
int32_t subscribeToAllVendorParams;
if (msg->findInt32("x-*", &subscribeToAllVendorParams) && subscribeToAllVendorParams) {
if (config->subscribeToAllVendorParams(comp, C2_MAY_BLOCK) != OK) {
@@ -1022,7 +1070,7 @@
sdkParams = msg->dup();
sdkParams->removeEntryAt(sdkParams->findEntryByName(PARAMETER_KEY_VIDEO_BITRATE));
}
- status_t err = config->getConfigUpdateFromSdkParams(
+ err = config->getConfigUpdateFromSdkParams(
comp, sdkParams, Config::IS_CONFIG, C2_DONT_BLOCK, &configUpdate);
if (err != OK) {
ALOGW("failed to convert configuration to c2 params");
@@ -1133,10 +1181,10 @@
int32_t clientPrepend;
if ((config->mDomain & Config::IS_VIDEO)
&& (config->mDomain & Config::IS_ENCODER)
- && msg->findInt32(KEY_PREPEND_HEADERS_TO_SYNC_FRAMES, &clientPrepend)
+ && msg->findInt32(KEY_PREPEND_HEADER_TO_SYNC_FRAMES, &clientPrepend)
&& clientPrepend
&& (!prepend || prepend.value != PREPEND_HEADER_TO_ALL_SYNC)) {
- ALOGE("Failed to set KEY_PREPEND_HEADERS_TO_SYNC_FRAMES");
+ ALOGE("Failed to set KEY_PREPEND_HEADER_TO_SYNC_FRAMES");
return BAD_VALUE;
}
@@ -1703,6 +1751,19 @@
}
status_t CCodec::setSurface(const sp<Surface> &surface) {
+ Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
+ const std::unique_ptr<Config> &config = *configLocked;
+ if (config->mTunneled && config->mSidebandHandle != nullptr) {
+ sp<ANativeWindow> nativeWindow = static_cast<ANativeWindow *>(surface.get());
+ status_t err = native_window_set_sideband_stream(
+ nativeWindow.get(),
+ const_cast<native_handle_t *>(config->mSidebandHandle->handle()));
+ if (err != OK) {
+ ALOGE("NativeWindow(%p) native_window_set_sideband_stream(%p) failed! (err %d).",
+ nativeWindow.get(), config->mSidebandHandle->handle(), err);
+ return err;
+ }
+ }
return mChannel->setSurface(surface);
}
@@ -1926,6 +1987,44 @@
}
}
+static void HandleDataspace(
+ android_dataspace dataspace, ColorAspects *colorAspects, sp<AMessage> *format) {
+ ColorUtils::convertDataSpaceToV0(dataspace);
+ int32_t range, standard, transfer;
+ range = (dataspace & HAL_DATASPACE_RANGE_MASK) >> HAL_DATASPACE_RANGE_SHIFT;
+ if (range == 0) {
+ range = ColorUtils::wrapColorAspectsIntoColorRange(
+ colorAspects->mRange);
+ }
+ standard = (dataspace & HAL_DATASPACE_STANDARD_MASK) >> HAL_DATASPACE_STANDARD_SHIFT;
+ if (standard == 0) {
+ standard = ColorUtils::wrapColorAspectsIntoColorStandard(
+ colorAspects->mPrimaries,
+ colorAspects->mMatrixCoeffs);
+ }
+ transfer = (dataspace & HAL_DATASPACE_TRANSFER_MASK) >> HAL_DATASPACE_TRANSFER_SHIFT;
+ if (transfer == 0) {
+ transfer = ColorUtils::wrapColorAspectsIntoColorTransfer(
+ colorAspects->mTransfer);
+ }
+ ColorAspects newColorAspects;
+ ColorUtils::convertPlatformColorAspectsToCodecAspects(
+ range, standard, transfer, newColorAspects);
+ if (ColorUtils::checkIfAspectsChangedAndUnspecifyThem(
+ newColorAspects, *colorAspects)) {
+ *format = (*format)->dup();
+ (*format)->setInt32(KEY_COLOR_RANGE, range);
+ (*format)->setInt32(KEY_COLOR_STANDARD, standard);
+ (*format)->setInt32(KEY_COLOR_TRANSFER, transfer);
+ // Record current color aspects into |colorAspects|.
+ // NOTE: newColorAspects could have been modified by
+ // checkIfAspectsChangedAndUnspecifyThem() above,
+ // so *colorAspects = newColorAspects does not work as intended.
+ ColorUtils::convertPlatformColorAspectsToCodecAspects(
+ range, standard, transfer, *colorAspects);
+ }
+}
+
void CCodec::onMessageReceived(const sp<AMessage> &msg) {
TimePoint now = std::chrono::steady_clock::now();
CCodecWatchdog::getInstance()->watch(this);
@@ -2040,6 +2139,10 @@
sp<AMessage> outputFormat = config->mOutputFormat;
config->updateConfiguration(updates, config->mOutputDomain);
+ if (config->mInputSurface) {
+ android_dataspace ds = config->mInputSurface->getDataspace();
+ HandleDataspace(ds, &config->mClientColorAspects, &config->mOutputFormat);
+ }
RevertOutputFormatIfNeeded(outputFormat, config->mOutputFormat);
// copy standard infos to graphic buffers if not already present (otherwise, we
@@ -2099,6 +2202,51 @@
deadline->set(now + (timeout * mult), name);
}
+status_t CCodec::configureTunneledVideoPlayback(
+ std::shared_ptr<Codec2Client::Component> comp,
+ sp<NativeHandle> *sidebandHandle,
+ const sp<AMessage> &msg) {
+ std::vector<std::unique_ptr<C2SettingResult>> failures;
+
+ std::unique_ptr<C2PortTunneledModeTuning::output> tunneledPlayback =
+ C2PortTunneledModeTuning::output::AllocUnique(
+ 1,
+ C2PortTunneledModeTuning::Struct::SIDEBAND,
+ C2PortTunneledModeTuning::Struct::REALTIME,
+ 0);
+ // TODO: use KEY_AUDIO_HW_SYNC, KEY_HARDWARE_AV_SYNC_ID when they are in MediaCodecConstants.h
+ if (msg->findInt32("audio-hw-sync", &tunneledPlayback->m.syncId[0])) {
+ tunneledPlayback->m.syncType = C2PortTunneledModeTuning::Struct::sync_type_t::AUDIO_HW_SYNC;
+ } else if (msg->findInt32("hw-av-sync-id", &tunneledPlayback->m.syncId[0])) {
+ tunneledPlayback->m.syncType = C2PortTunneledModeTuning::Struct::sync_type_t::HW_AV_SYNC;
+ } else {
+ tunneledPlayback->m.syncType = C2PortTunneledModeTuning::Struct::sync_type_t::REALTIME;
+ tunneledPlayback->setFlexCount(0);
+ }
+ c2_status_t c2err = comp->config({ tunneledPlayback.get() }, C2_MAY_BLOCK, &failures);
+ if (c2err != C2_OK) {
+ return UNKNOWN_ERROR;
+ }
+
+ std::vector<std::unique_ptr<C2Param>> params;
+ c2err = comp->query({}, {C2PortTunnelHandleTuning::output::PARAM_TYPE}, C2_DONT_BLOCK, ¶ms);
+ if (c2err == C2_OK && params.size() == 1u) {
+ C2PortTunnelHandleTuning::output *videoTunnelSideband =
+ C2PortTunnelHandleTuning::output::From(params[0].get());
+ // Currently, Codec2 only supports non-fd case for sideband native_handle.
+ native_handle_t *handle = native_handle_create(0, videoTunnelSideband->flexCount());
+ *sidebandHandle = NativeHandle::create(handle, true /* ownsHandle */);
+ if (handle != nullptr && videoTunnelSideband->flexCount()) {
+ memcpy(handle->data, videoTunnelSideband->m.values,
+ sizeof(int32_t) * videoTunnelSideband->flexCount());
+ return OK;
+ } else {
+ return NO_MEMORY;
+ }
+ }
+ return UNKNOWN_ERROR;
+}
+
void CCodec::initiateReleaseIfStuck() {
std::string name;
bool pendingDeadline = false;
@@ -2111,7 +2259,9 @@
pendingDeadline = true;
}
}
- if (name.empty()) {
+ Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
+ const std::unique_ptr<Config> &config = *configLocked;
+ if (config->mTunneled == false && name.empty()) {
constexpr std::chrono::steady_clock::duration kWorkDurationThreshold = 3s;
std::chrono::steady_clock::duration elapsed = mChannel->elapsed();
if (elapsed >= kWorkDurationThreshold) {
@@ -2504,4 +2654,3 @@
}
} // namespace android
-
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 44ebf84..3f717c9 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -1728,6 +1728,17 @@
}
break;
}
+ case C2PortTunnelSystemTime::CORE_INDEX: {
+ C2PortTunnelSystemTime::output frameRenderTime;
+ if (frameRenderTime.updateFrom(*param)) {
+ ALOGV("[%s] onWorkDone: frame rendered (sys:%lld ns, media:%lld us)",
+ mName, (long long)frameRenderTime.value,
+ (long long)worklet->output.ordinal.timestamp.peekll());
+ mCCodecCallback->onOutputFramesRendered(
+ worklet->output.ordinal.timestamp.peek(), frameRenderTime.value);
+ }
+ break;
+ }
default:
ALOGV("[%s] onWorkDone: unrecognized config update (%08X)",
mName, param->index());
diff --git a/media/codec2/sfplugin/CCodecConfig.cpp b/media/codec2/sfplugin/CCodecConfig.cpp
index d3814fb..5de7539 100644
--- a/media/codec2/sfplugin/CCodecConfig.cpp
+++ b/media/codec2/sfplugin/CCodecConfig.cpp
@@ -18,6 +18,7 @@
#define LOG_TAG "CCodecConfig"
#include <cutils/properties.h>
#include <log/log.h>
+#include <utils/NativeHandle.h>
#include <C2Component.h>
#include <C2Param.h>
@@ -321,7 +322,8 @@
CCodecConfig::CCodecConfig()
: mInputFormat(new AMessage),
mOutputFormat(new AMessage),
- mUsingSurface(false) { }
+ mUsingSurface(false),
+ mTunneled(false) { }
void CCodecConfig::initializeStandardParams() {
typedef Domain D;
@@ -507,7 +509,7 @@
add(ConfigMapper(std::string(KEY_FEATURE_) + FEATURE_SecurePlayback,
C2_PARAMKEY_SECURE_MODE, "value"));
- add(ConfigMapper(KEY_PREPEND_HEADERS_TO_SYNC_FRAMES,
+ add(ConfigMapper(KEY_PREPEND_HEADER_TO_SYNC_FRAMES,
C2_PARAMKEY_PREPEND_HEADER_MODE, "value")
.limitTo(D::ENCODER & D::VIDEO)
.withMappers([](C2Value v) -> C2Value {
@@ -531,7 +533,7 @@
return C2Value();
}));
// remove when codecs switch to PARAMKEY
- deprecated(ConfigMapper(KEY_PREPEND_HEADERS_TO_SYNC_FRAMES,
+ deprecated(ConfigMapper(KEY_PREPEND_HEADER_TO_SYNC_FRAMES,
"coding.add-csd-to-sync-frames", "value")
.limitTo(D::ENCODER & D::VIDEO));
// convert to timestamp base
@@ -727,6 +729,19 @@
return C2Value();
}));
+ add(ConfigMapper(KEY_VIDEO_QP_I_MAX, C2_PARAMKEY_QUANTIZATION, "i-max")
+ .limitTo(D::VIDEO & D::ENCODER));
+ add(ConfigMapper(KEY_VIDEO_QP_I_MIN, C2_PARAMKEY_QUANTIZATION, "i-min")
+ .limitTo(D::VIDEO & D::ENCODER));
+ add(ConfigMapper(KEY_VIDEO_QP_P_MAX, C2_PARAMKEY_QUANTIZATION, "p-max")
+ .limitTo(D::VIDEO & D::ENCODER));
+ add(ConfigMapper(KEY_VIDEO_QP_P_MIN, C2_PARAMKEY_QUANTIZATION, "p-min")
+ .limitTo(D::VIDEO & D::ENCODER));
+ add(ConfigMapper(KEY_VIDEO_QP_B_MAX, C2_PARAMKEY_QUANTIZATION, "b-max")
+ .limitTo(D::VIDEO & D::ENCODER));
+ add(ConfigMapper(KEY_VIDEO_QP_B_MIN, C2_PARAMKEY_QUANTIZATION, "b-min")
+ .limitTo(D::VIDEO & D::ENCODER));
+
// convert to dBFS and add default
add(ConfigMapper(KEY_AAC_DRC_TARGET_REFERENCE_LEVEL, C2_PARAMKEY_DRC_TARGET_REFERENCE_LEVEL, "value")
.limitTo(D::AUDIO & D::DECODER & (D::CONFIG | D::PARAM | D::READ))
diff --git a/media/codec2/sfplugin/CCodecConfig.h b/media/codec2/sfplugin/CCodecConfig.h
index 2895746..d9116f7 100644
--- a/media/codec2/sfplugin/CCodecConfig.h
+++ b/media/codec2/sfplugin/CCodecConfig.h
@@ -27,6 +27,7 @@
#include <C2Debug.h>
#include <codec2/hidl/client.h>
+#include <media/stagefright/foundation/ColorUtils.h>
#include <utils/RefBase.h>
#include "InputSurfaceWrapper.h"
@@ -35,6 +36,7 @@
namespace android {
struct AMessage;
+class NativeHandle;
struct StandardParams;
/**
@@ -123,6 +125,7 @@
std::shared_ptr<InputSurfaceWrapper> mInputSurface;
std::unique_ptr<InputSurfaceWrapper::Config> mISConfig;
+ ColorAspects mClientColorAspects;
/// the current configuration. Updated after configure() and based on configUpdate in
/// onWorkDone
@@ -141,6 +144,10 @@
std::set<std::string> mLastConfig;
+ /// Tunneled codecs
+ bool mTunneled;
+ sp<NativeHandle> mSidebandHandle;
+
CCodecConfig();
/// initializes the members required to manage the format: descriptors, reflector,
diff --git a/media/codec2/sfplugin/Codec2Buffer.cpp b/media/codec2/sfplugin/Codec2Buffer.cpp
index fc4ee51..34e6a88 100644
--- a/media/codec2/sfplugin/Codec2Buffer.cpp
+++ b/media/codec2/sfplugin/Codec2Buffer.cpp
@@ -713,6 +713,8 @@
c2_status_t err = mAlloc->priorGraphicAllocation(handle, &alloc);
if (err != C2_OK) {
ALOGD("Failed to wrap VideoNativeMetadata into C2GraphicAllocation");
+ native_handle_close(handle);
+ native_handle_delete(handle);
return nullptr;
}
std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(alloc);
diff --git a/media/codec2/sfplugin/InputSurfaceWrapper.h b/media/codec2/sfplugin/InputSurfaceWrapper.h
index 479acb1..d29738c 100644
--- a/media/codec2/sfplugin/InputSurfaceWrapper.h
+++ b/media/codec2/sfplugin/InputSurfaceWrapper.h
@@ -106,6 +106,8 @@
*/
virtual void onInputBufferDone(c2_cntr64_t /* index */) {}
+ virtual android_dataspace getDataspace() { return mDataSpace; }
+
protected:
android_dataspace mDataSpace;
};
diff --git a/media/codec2/sfplugin/include/media/stagefright/CCodec.h b/media/codec2/sfplugin/include/media/stagefright/CCodec.h
index dbbb5d5..ba69d7e 100644
--- a/media/codec2/sfplugin/include/media/stagefright/CCodec.h
+++ b/media/codec2/sfplugin/include/media/stagefright/CCodec.h
@@ -126,6 +126,11 @@
const std::chrono::milliseconds &timeout,
const char *name);
+ status_t configureTunneledVideoPlayback(
+ const std::shared_ptr<Codec2Client::Component> comp,
+ sp<NativeHandle> *sidebandHandle,
+ const sp<AMessage> &msg);
+
enum {
kWhatAllocate,
kWhatConfigure,
diff --git a/media/codec2/tests/vndk/C2BufferTest.cpp b/media/codec2/tests/vndk/C2BufferTest.cpp
index a9f8e17..0cfb465 100644
--- a/media/codec2/tests/vndk/C2BufferTest.cpp
+++ b/media/codec2/tests/vndk/C2BufferTest.cpp
@@ -16,11 +16,12 @@
#include <gtest/gtest.h>
-#include <C2AllocatorIon.h>
#include <C2AllocatorGralloc.h>
#include <C2Buffer.h>
#include <C2BufferPriv.h>
+#include <C2Config.h>
#include <C2ParamDef.h>
+#include <C2PlatformSupport.h>
#include <system/graphics.h>
@@ -233,10 +234,10 @@
public:
C2BufferTest()
: mBlockPoolId(C2BlockPool::PLATFORM_START),
- mLinearAllocator(std::make_shared<C2AllocatorIon>('i')),
mSize(0u),
mAddr(nullptr),
mGraphicAllocator(std::make_shared<C2AllocatorGralloc>('g')) {
+ getLinearAllocator(&mLinearAllocator);
}
~C2BufferTest() = default;
@@ -329,6 +330,11 @@
}
private:
+ void getLinearAllocator(std::shared_ptr<C2Allocator>* mLinearAllocator) {
+ std::shared_ptr<C2AllocatorStore> store = android::GetCodec2PlatformAllocatorStore();
+ ASSERT_EQ(store->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, mLinearAllocator), C2_OK);
+ }
+
C2BlockPool::local_id_t mBlockPoolId;
std::shared_ptr<C2Allocator> mLinearAllocator;
std::shared_ptr<C2LinearAllocation> mLinearAllocation;
diff --git a/media/codec2/vndk/include/C2AllocatorGralloc.h b/media/codec2/vndk/include/C2AllocatorGralloc.h
index 578cf76..1da3e14 100644
--- a/media/codec2/vndk/include/C2AllocatorGralloc.h
+++ b/media/codec2/vndk/include/C2AllocatorGralloc.h
@@ -37,7 +37,8 @@
* Wrap the gralloc handle and metadata into Codec2 handle recognized by
* C2AllocatorGralloc.
*
- * @return a new NON-OWNING C2Handle that must be deleted using native_handle_delete.
+ * @return a new NON-OWNING C2Handle that must be closed and deleted using native_handle_close and
+ * native_handle_delete.
*/
C2Handle *WrapNativeCodec2GrallocHandle(
const native_handle_t *const handle,
diff --git a/media/codec2/vndk/platform/C2BqBuffer.cpp b/media/codec2/vndk/platform/C2BqBuffer.cpp
index e14b4b1..3f6fa7d 100644
--- a/media/codec2/vndk/platform/C2BqBuffer.cpp
+++ b/media/codec2/vndk/platform/C2BqBuffer.cpp
@@ -364,6 +364,8 @@
std::shared_ptr<C2GraphicAllocation> alloc;
c2_status_t err = mAllocator->priorGraphicAllocation(c2Handle, &alloc);
if (err != C2_OK) {
+ native_handle_close(c2Handle);
+ native_handle_delete(c2Handle);
return err;
}
std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
diff --git a/media/janitors/OWNERS-codecs b/media/janitors/codec_OWNERS
similarity index 100%
rename from media/janitors/OWNERS-codecs
rename to media/janitors/codec_OWNERS
diff --git a/media/libaaudio/include/aaudio/AAudio.h b/media/libaaudio/include/aaudio/AAudio.h
index 9072886..22cf254 100644
--- a/media/libaaudio/include/aaudio/AAudio.h
+++ b/media/libaaudio/include/aaudio/AAudio.h
@@ -580,6 +580,37 @@
AAUDIO_API void AAudioStreamBuilder_setDeviceId(AAudioStreamBuilder* builder,
int32_t deviceId) __INTRODUCED_IN(26);
+// TODO b/182392769: reexamine if Identity can be used
+/**
+ * Declare the name of the package creating the stream.
+ *
+ * This is usually {@code Context#getPackageName()}.
+ *
+ * The default, if you do not call this function, is a random package in the calling uid.
+ *
+ * Available since API level 31.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder()
+ * @param packageName packageName of the calling app.
+ */
+AAUDIO_API void AAudioStreamBuilder_setPackageName(AAudioStreamBuilder* builder,
+ const char * packageName) __INTRODUCED_IN(31);
+
+/**
+ * Declare the attribution tag of the context creating the stream.
+ *
+ * This is usually {@code Context#getAttributionTag()}.
+ *
+ * The default, if you do not call this function, is the default attribution tag.
+ *
+ * Available since API level 31.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder()
+ * @param attributionTag attributionTag of the calling context.
+ */
+AAUDIO_API void AAudioStreamBuilder_setAttributionTag(AAudioStreamBuilder* builder,
+ const char * attributionTag) __INTRODUCED_IN(31);
+
/**
* Request a sample rate in Hertz.
*
diff --git a/media/libaaudio/src/Android.bp b/media/libaaudio/src/Android.bp
index 47cbbb1..fe2d98e 100644
--- a/media/libaaudio/src/Android.bp
+++ b/media/libaaudio/src/Android.bp
@@ -85,6 +85,10 @@
],
export_header_lib_headers: ["libaaudio_headers"],
+ export_shared_lib_headers: [
+ "media_permission-aidl-cpp",
+ ],
+
shared_libs: [
"libaudioclient",
"libaudioutils",
@@ -96,6 +100,12 @@
"libutils",
"libbinder",
"aaudio-aidl-cpp",
+ "media_permission-aidl-cpp",
+ "libaudioclient_aidl_conversion",
+ ],
+
+ static_libs: [
+ "media_permission-aidl-cpp",
],
cflags: [
@@ -167,6 +177,7 @@
imports: [
"audio_common-aidl",
"shared-file-region-aidl",
+ "media_permission-aidl",
],
backend:
{
diff --git a/media/libaaudio/src/binding/AAudioStreamRequest.cpp b/media/libaaudio/src/binding/AAudioStreamRequest.cpp
index 536395a..5e0a4bb 100644
--- a/media/libaaudio/src/binding/AAudioStreamRequest.cpp
+++ b/media/libaaudio/src/binding/AAudioStreamRequest.cpp
@@ -31,19 +31,15 @@
AAudioStreamRequest::AAudioStreamRequest(const StreamRequest& parcelable) :
mConfiguration(std::move(parcelable.params)),
- mUserId(parcelable.userId),
- mProcessId(parcelable.processId),
+ mIdentity(parcelable.identity),
mSharingModeMatchRequired(parcelable.sharingModeMatchRequired),
mInService(parcelable.inService) {
- static_assert(sizeof(mUserId) == sizeof(parcelable.userId));
- static_assert(sizeof(mProcessId) == sizeof(parcelable.processId));
}
StreamRequest AAudioStreamRequest::parcelable() const {
StreamRequest result;
result.params = std::move(mConfiguration).parcelable();
- result.userId = mUserId;
- result.processId = mProcessId;
+ result.identity = mIdentity;
result.sharingModeMatchRequired = mSharingModeMatchRequired;
result.inService = mInService;
return result;
@@ -54,8 +50,7 @@
}
void AAudioStreamRequest::dump() const {
- ALOGD("mUserId = %d", mUserId);
- ALOGD("mProcessId = %d", mProcessId);
+ ALOGD("mIdentity = %s", mIdentity.toString().c_str());
ALOGD("mSharingModeMatchRequired = %d", mSharingModeMatchRequired);
ALOGD("mInService = %d", mInService);
mConfiguration.dump();
diff --git a/media/libaaudio/src/binding/AAudioStreamRequest.h b/media/libaaudio/src/binding/AAudioStreamRequest.h
index 31d3ea1..02341c8 100644
--- a/media/libaaudio/src/binding/AAudioStreamRequest.h
+++ b/media/libaaudio/src/binding/AAudioStreamRequest.h
@@ -23,6 +23,7 @@
#include <aaudio/StreamRequest.h>
#include "binding/AAudioStreamConfiguration.h"
+#include <android/media/permission/Identity.h>
namespace aaudio {
@@ -33,20 +34,12 @@
// Construct based on a parcelable representation.
explicit AAudioStreamRequest(const StreamRequest& parcelable);
- uid_t getUserId() const {
- return mUserId;
+ const android::media::permission::Identity &getIdentity() const {
+ return mIdentity;
}
- void setUserId(uid_t userId) {
- mUserId = userId;
- }
-
- pid_t getProcessId() const {
- return mProcessId;
- }
-
- void setProcessId(pid_t processId) {
- mProcessId = processId;
+ void setIdentity(const android::media::permission::Identity &identity) {
+ mIdentity = identity;
}
bool isSharingModeMatchRequired() const {
@@ -82,8 +75,7 @@
private:
AAudioStreamConfiguration mConfiguration;
- uid_t mUserId = (uid_t) -1;
- pid_t mProcessId = (pid_t) -1;
+ android::media::permission::Identity mIdentity;
bool mSharingModeMatchRequired = false;
bool mInService = false; // Stream opened by AAudioservice
};
diff --git a/media/libaaudio/src/binding/aidl/aaudio/StreamRequest.aidl b/media/libaaudio/src/binding/aidl/aaudio/StreamRequest.aidl
index 9bf4077..12802e6 100644
--- a/media/libaaudio/src/binding/aidl/aaudio/StreamRequest.aidl
+++ b/media/libaaudio/src/binding/aidl/aaudio/StreamRequest.aidl
@@ -17,11 +17,11 @@
package aaudio;
import aaudio.StreamParameters;
+import android.media.permission.Identity;
parcelable StreamRequest {
StreamParameters params;
- int userId; // = (uid_t) -1;
- int processId; // = (pid_t) -1;
+ Identity identity;
boolean sharingModeMatchRequired; // = false;
boolean inService; // = false; // Stream opened by AAudioservice
}
\ No newline at end of file
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 2815c6a..dc961ad 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -28,7 +28,6 @@
#include <cutils/properties.h>
#include <media/MediaMetricsItem.h>
-#include <utils/String16.h>
#include <utils/Trace.h>
#include "AudioEndpointParcelable.h"
@@ -39,6 +38,7 @@
#include "core/AudioStreamBuilder.h"
#include "fifo/FifoBuffer.h"
#include "utility/AudioClock.h"
+#include <media/AidlConversion.h>
#include "AudioStreamInternal.h"
@@ -49,9 +49,9 @@
// This is needed to make sense of the logs more easily.
#define LOG_TAG (mInService ? "AudioStreamInternal_Service" : "AudioStreamInternal_Client")
-using android::String16;
using android::Mutex;
using android::WrappingBuffer;
+using android::media::permission::Identity;
using namespace aaudio;
@@ -107,9 +107,15 @@
// Request FLOAT for the shared mixer or the device.
request.getConfiguration().setFormat(AUDIO_FORMAT_PCM_FLOAT);
+ // TODO b/182392769: use identity util
+ Identity identity;
+ identity.uid = VALUE_OR_FATAL(android::legacy2aidl_uid_t_int32_t(getuid()));
+ identity.pid = VALUE_OR_FATAL(android::legacy2aidl_pid_t_int32_t(getpid()));
+ identity.packageName = builder.getOpPackageName();
+ identity.attributionTag = builder.getAttributionTag();
+
// Build the request to send to the server.
- request.setUserId(getuid());
- request.setProcessId(getpid());
+ request.setIdentity(identity);
request.setSharingModeMatchRequired(isSharingModeMatchRequired());
request.setInService(isInService());
diff --git a/media/libaaudio/src/core/AAudioAudio.cpp b/media/libaaudio/src/core/AAudioAudio.cpp
index 7c16321..5d49759 100644
--- a/media/libaaudio/src/core/AAudioAudio.cpp
+++ b/media/libaaudio/src/core/AAudioAudio.cpp
@@ -87,6 +87,22 @@
streamBuilder->setDeviceId(deviceId);
}
+AAUDIO_API void AAudioStreamBuilder_setPackageName(AAudioStreamBuilder* builder,
+ const char* packageName)
+{
+ AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
+ // Only system apps can read the op package name. For regular apps the regular package name
+ // is a sufficient replacement
+ streamBuilder->setOpPackageName(packageName);
+}
+
+AAUDIO_API void AAudioStreamBuilder_setAttributionTag(AAudioStreamBuilder* builder,
+ const char* attributionTag)
+{
+ AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
+ streamBuilder->setAttributionTag(attributionTag);
+}
+
AAUDIO_API void AAudioStreamBuilder_setSampleRate(AAudioStreamBuilder* builder,
int32_t sampleRate)
{
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.cpp b/media/libaaudio/src/core/AAudioStreamParameters.cpp
index 2c81c91..0d60120 100644
--- a/media/libaaudio/src/core/AAudioStreamParameters.cpp
+++ b/media/libaaudio/src/core/AAudioStreamParameters.cpp
@@ -48,6 +48,8 @@
mInputPreset = other.mInputPreset;
mAllowedCapturePolicy = other.mAllowedCapturePolicy;
mIsPrivacySensitive = other.mIsPrivacySensitive;
+ mOpPackageName = other.mOpPackageName;
+ mAttributionTag = other.mAttributionTag;
}
static aaudio_result_t isFormatValid(audio_format_t format) {
@@ -203,4 +205,8 @@
ALOGD("mInputPreset = %6d", mInputPreset);
ALOGD("mAllowedCapturePolicy = %6d", mAllowedCapturePolicy);
ALOGD("mIsPrivacySensitive = %s", mIsPrivacySensitive ? "true" : "false");
+ ALOGD("mOpPackageName = %s", !mOpPackageName.has_value() ?
+ "(null)" : mOpPackageName.value().c_str());
+ ALOGD("mAttributionTag = %s", !mAttributionTag.has_value() ?
+ "(null)" : mAttributionTag.value().c_str());
}
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.h b/media/libaaudio/src/core/AAudioStreamParameters.h
index 3e65b37..bb39d8b 100644
--- a/media/libaaudio/src/core/AAudioStreamParameters.h
+++ b/media/libaaudio/src/core/AAudioStreamParameters.h
@@ -136,6 +136,23 @@
mIsPrivacySensitive = privacySensitive;
}
+ const std::optional<std::string> getOpPackageName() const {
+ return mOpPackageName;
+ }
+
+ // TODO b/182392769: reexamine if Identity can be used
+ void setOpPackageName(const std::string opPackageName) {
+ mOpPackageName = opPackageName;
+ }
+
+ const std::optional<std::string> getAttributionTag() const {
+ return mAttributionTag;
+ }
+
+ void setAttributionTag(const std::string attributionTag) {
+ mAttributionTag = attributionTag;
+ }
+
/**
* @return bytes per frame of getFormat()
*/
@@ -167,6 +184,8 @@
aaudio_allowed_capture_policy_t mAllowedCapturePolicy = AAUDIO_UNSPECIFIED;
aaudio_session_id_t mSessionId = AAUDIO_SESSION_ID_NONE;
bool mIsPrivacySensitive = false;
+ std::optional<std::string> mOpPackageName = {};
+ std::optional<std::string> mAttributionTag = {};
};
} /* namespace aaudio */
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.cpp b/media/libaaudio/src/core/AudioStreamBuilder.cpp
index 50a3b38..207a8e3 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.cpp
+++ b/media/libaaudio/src/core/AudioStreamBuilder.cpp
@@ -282,4 +282,8 @@
ALOGI("usage = %6d, contentType = %d, inputPreset = %d, allowedCapturePolicy = %d",
getUsage(), getContentType(), getInputPreset(), getAllowedCapturePolicy());
ALOGI("privacy sensitive = %s", isPrivacySensitive() ? "true" : "false");
+ ALOGI("opPackageName = %s", !getOpPackageName().has_value() ?
+ "(null)" : getOpPackageName().value().c_str());
+ ALOGI("attributionTag = %s", !getAttributionTag().has_value() ?
+ "(null)" : getAttributionTag().value().c_str());
}
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index 45b2258..7733a04 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -22,6 +22,7 @@
#include <aaudio/AAudio.h>
#include <audio_utils/primitives.h>
+#include <media/AidlConversion.h>
#include <media/AudioRecord.h>
#include <utils/String16.h>
@@ -30,6 +31,8 @@
#include "utility/AudioClock.h"
#include "utility/FixedBlockWriter.h"
+using android::media::permission::Identity;
+
using namespace android;
using namespace aaudio;
@@ -152,13 +155,20 @@
.tags = ""
};
+ // TODO b/182392769: use identity util
+ Identity identity;
+ identity.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(getuid()));
+ identity.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(getpid()));
+ identity.packageName = builder.getOpPackageName();
+ identity.attributionTag = builder.getAttributionTag();
+
// ----------- open the AudioRecord ---------------------
// Might retry, but never more than once.
for (int i = 0; i < 2; i ++) {
const audio_format_t requestedInternalFormat = getDeviceFormat();
mAudioRecord = new AudioRecord(
- mOpPackageName // const String16& opPackageName TODO does not compile
+ identity
);
mAudioRecord->set(
AUDIO_SOURCE_DEFAULT, // ignored because we pass attributes below
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.h b/media/libaaudio/src/legacy/AudioStreamRecord.h
index b2f8ba5..7d0a197 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.h
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.h
@@ -25,6 +25,7 @@
#include "AAudioLegacy.h"
#include "legacy/AudioStreamLegacy.h"
#include "utility/FixedBlockWriter.h"
+#include <android/media/permission/Identity.h>
namespace aaudio {
@@ -86,7 +87,7 @@
FixedBlockWriter mFixedBlockWriter;
// TODO add 64-bit position reporting to AudioRecord and use it.
- android::String16 mOpPackageName;
+ android::media::permission::Identity mIdentity;
// Only one type of conversion buffer is used.
std::unique_ptr<float[]> mFormatConversionBufferFloat;
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index af8ff19..142a85c 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -31,6 +31,8 @@
using namespace android;
using namespace aaudio;
+using media::permission::Identity;
+
// Arbitrary and somewhat generous number of bursts.
#define DEFAULT_BURSTS_PER_BUFFER_CAPACITY 8
@@ -147,6 +149,7 @@
};
mAudioTrack = new AudioTrack();
+ // TODO b/182392769: use identity util
mAudioTrack->set(
AUDIO_STREAM_DEFAULT, // ignored because we pass attributes below
getSampleRate(),
@@ -162,8 +165,7 @@
sessionId,
streamTransferType,
NULL, // DEFAULT audio_offload_info_t
- AUDIO_UID_INVALID, // DEFAULT uid
- -1, // DEFAULT pid
+ Identity(), // DEFAULT uid and pid
&attributes,
// WARNING - If doNotReconnect set true then audio stops after plugging and unplugging
// headphones a few times.
diff --git a/media/libaaudio/src/libaaudio.map.txt b/media/libaaudio/src/libaaudio.map.txt
index 2e00aa5..1dd44d1 100644
--- a/media/libaaudio/src/libaaudio.map.txt
+++ b/media/libaaudio/src/libaaudio.map.txt
@@ -23,6 +23,8 @@
AAudioStreamBuilder_setAllowedCapturePolicy; # introduced=29
AAudioStreamBuilder_setSessionId; # introduced=28
AAudioStreamBuilder_setPrivacySensitive; # introduced=30
+ AAudioStreamBuilder_setPackageName; # introduced=31
+ AAudioStreamBuilder_setAttributionTag; # introduced=31
AAudioStreamBuilder_openStream;
AAudioStreamBuilder_delete;
AAudioStream_close;
diff --git a/media/libaudioclient/AidlConversion.cpp b/media/libaudioclient/AidlConversion.cpp
index 4c0db3e..05ba55f 100644
--- a/media/libaudioclient/AidlConversion.cpp
+++ b/media/libaudioclient/AidlConversion.cpp
@@ -190,6 +190,27 @@
return std::string(String8(legacy).c_str());
}
+// TODO b/182392769: create an optional -> optional util
+ConversionResult<std::optional<String16>>
+aidl2legacy_optional_string_view_optional_String16(std::optional<std::string_view> aidl) {
+ if (!aidl.has_value()) {
+ return std::nullopt;
+ }
+ ConversionResult<String16> conversion =
+ VALUE_OR_RETURN(aidl2legacy_string_view_String16(aidl.value()));
+ return conversion.value();
+}
+
+ConversionResult<std::optional<std::string_view>>
+legacy2aidl_optional_String16_optional_string(std::optional<String16> legacy) {
+ if (!legacy.has_value()) {
+ return std::nullopt;
+ }
+ ConversionResult<std::string> conversion =
+ VALUE_OR_RETURN(legacy2aidl_String16_string(legacy.value()));
+ return conversion.value();
+}
+
ConversionResult<String8> aidl2legacy_string_view_String8(std::string_view aidl) {
return String8(aidl.data(), aidl.size());
}
@@ -1160,20 +1181,16 @@
ConversionResult<AudioClient> aidl2legacy_AudioClient_AudioClient(
const media::AudioClient& aidl) {
AudioClient legacy;
- legacy.clientUid = VALUE_OR_RETURN(aidl2legacy_int32_t_uid_t(aidl.clientUid));
- legacy.clientPid = VALUE_OR_RETURN(aidl2legacy_int32_t_pid_t(aidl.clientPid));
legacy.clientTid = VALUE_OR_RETURN(aidl2legacy_int32_t_pid_t(aidl.clientTid));
- legacy.packageName = VALUE_OR_RETURN(aidl2legacy_string_view_String16(aidl.packageName));
+ legacy.identity = aidl.identity;
return legacy;
}
ConversionResult<media::AudioClient> legacy2aidl_AudioClient_AudioClient(
const AudioClient& legacy) {
media::AudioClient aidl;
- aidl.clientUid = VALUE_OR_RETURN(legacy2aidl_uid_t_int32_t(legacy.clientUid));
- aidl.clientPid = VALUE_OR_RETURN(legacy2aidl_pid_t_int32_t(legacy.clientPid));
aidl.clientTid = VALUE_OR_RETURN(legacy2aidl_pid_t_int32_t(legacy.clientTid));
- aidl.packageName = VALUE_OR_RETURN(legacy2aidl_String16_string(legacy.packageName));
+ aidl.identity = legacy.identity;
return aidl;
}
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index 79c155e..d25597d 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -132,10 +132,12 @@
"libshmemcompat",
"libutils",
"libvibrator",
+ "media_permission-aidl-cpp",
],
export_shared_lib_headers: [
"audioflinger-aidl-cpp",
"audiopolicy-aidl-cpp",
+ "media_permission-aidl-cpp",
"libbinder",
],
@@ -162,6 +164,7 @@
// for memory heap analysis
"libc_malloc_debug_backtrace",
"shared-file-region-aidl-cpp",
+ "media_permission-aidl-cpp",
],
cflags: [
"-Wall",
@@ -229,6 +232,7 @@
"libshmemcompat",
"libutils",
"shared-file-region-aidl-cpp",
+ "media_permission-aidl-cpp",
],
export_shared_lib_headers: [
"audioclient-types-aidl-cpp",
@@ -346,6 +350,7 @@
],
imports: [
"audio_common-aidl",
+ "media_permission-aidl",
],
backend: {
cpp: {
@@ -427,6 +432,7 @@
"av-types-aidl",
"effect-aidl",
"shared-file-region-aidl",
+ "media_permission-aidl",
],
double_loadable: true,
backend: {
@@ -460,6 +466,7 @@
"audioclient-types-aidl",
"audiopolicy-types-aidl",
"capture_state_listener-aidl",
+ "media_permission-aidl",
],
double_loadable: true,
backend: {
diff --git a/media/libaudioclient/AudioEffect.cpp b/media/libaudioclient/AudioEffect.cpp
index ad8ad7b..d5047b1 100644
--- a/media/libaudioclient/AudioEffect.cpp
+++ b/media/libaudioclient/AudioEffect.cpp
@@ -42,6 +42,7 @@
using aidl_utils::statusTFromBinderStatus;
using binder::Status;
using media::IAudioPolicyService;
+using media::permission::Identity;
namespace {
@@ -57,8 +58,8 @@
// ---------------------------------------------------------------------------
-AudioEffect::AudioEffect(const String16& opPackageName)
- : mOpPackageName(opPackageName)
+AudioEffect::AudioEffect(const Identity& identity)
+ : mClientIdentity(identity)
{
}
@@ -107,9 +108,12 @@
mDescriptor.type = *(type != NULL ? type : EFFECT_UUID_NULL);
mDescriptor.uuid = *(uuid != NULL ? uuid : EFFECT_UUID_NULL);
+ // TODO b/182392769: use identity util
mIEffectClient = new EffectClient(this);
- mClientPid = IPCThreadState::self()->getCallingPid();
- mClientUid = IPCThreadState::self()->getCallingUid();
+ pid_t pid = IPCThreadState::self()->getCallingPid();
+ mClientIdentity.pid = VALUE_OR_RETURN_STATUS(legacy2aidl_pid_t_int32_t(pid));
+ pid_t uid = IPCThreadState::self()->getCallingUid();
+ mClientIdentity.uid = VALUE_OR_RETURN_STATUS(legacy2aidl_uid_t_int32_t(uid));
media::CreateEffectRequest request;
request.desc = VALUE_OR_RETURN_STATUS(
@@ -119,8 +123,7 @@
request.output = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_io_handle_t_int32_t(io));
request.sessionId = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_session_t_int32_t(mSessionId));
request.device = VALUE_OR_RETURN_STATUS(legacy2aidl_AudioDeviceTypeAddress(device));
- request.opPackageName = VALUE_OR_RETURN_STATUS(legacy2aidl_String16_string(mOpPackageName));
- request.pid = VALUE_OR_RETURN_STATUS(legacy2aidl_pid_t_int32_t(mClientPid));
+ request.identity = mClientIdentity;
request.probe = probe;
media::CreateEffectResponse response;
@@ -175,10 +178,10 @@
IInterface::asBinder(iEffect)->linkToDeath(mIEffectClient);
ALOGV("set() %p OK effect: %s id: %d status %d enabled %d pid %d", this, mDescriptor.name, mId,
- mStatus, mEnabled, mClientPid);
+ mStatus, mEnabled, mClientIdentity.pid);
if (!audio_is_global_session(mSessionId)) {
- AudioSystem::acquireAudioSessionId(mSessionId, mClientPid, mClientUid);
+ AudioSystem::acquireAudioSessionId(mSessionId, pid, uid);
}
return mStatus;
@@ -219,7 +222,8 @@
if (!mProbe && (mStatus == NO_ERROR || mStatus == ALREADY_EXISTS)) {
if (!audio_is_global_session(mSessionId)) {
- AudioSystem::releaseAudioSessionId(mSessionId, mClientPid);
+ AudioSystem::releaseAudioSessionId(mSessionId,
+ VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(mClientIdentity.pid)));
}
if (mIEffect != NULL) {
mIEffect->disconnect();
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index 00ed3b8..e15ef3d 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -35,18 +35,11 @@
#include <media/MediaMetricsItem.h>
#include <media/TypeConverter.h>
-#define VALUE_OR_FATAL(result) \
- ({ \
- auto _tmp = (result); \
- LOG_ALWAYS_FATAL_IF(!_tmp.ok(), \
- "Failed result (%d)", \
- _tmp.error()); \
- std::move(_tmp.value()); \
- })
-
#define WAIT_PERIOD_MS 10
namespace android {
+
+using android::media::permission::Identity;
using aidl_utils::statusTFromBinderStatus;
// ---------------------------------------------------------------------------
@@ -133,9 +126,8 @@
return NO_ERROR;
}
-AudioRecord::AudioRecord(const String16 &opPackageName)
- : mActive(false), mStatus(NO_INIT), mOpPackageName(opPackageName),
- mSessionId(AUDIO_SESSION_ALLOCATE),
+AudioRecord::AudioRecord(const Identity &client)
+ : mActive(false), mStatus(NO_INIT), mClientIdentity(client), mSessionId(AUDIO_SESSION_ALLOCATE),
mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT),
mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE), mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE),
mSelectedMicDirection(MIC_DIRECTION_UNSPECIFIED),
@@ -148,7 +140,7 @@
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
- const String16& opPackageName,
+ const Identity& client,
size_t frameCount,
callback_t cbf,
void* user,
@@ -156,24 +148,24 @@
audio_session_t sessionId,
transfer_type transferType,
audio_input_flags_t flags,
- uid_t uid,
- pid_t pid,
const audio_attributes_t* pAttributes,
audio_port_handle_t selectedDeviceId,
audio_microphone_direction_t selectedMicDirection,
float microphoneFieldDimension)
: mActive(false),
mStatus(NO_INIT),
- mOpPackageName(opPackageName),
+ mClientIdentity(client),
mSessionId(AUDIO_SESSION_ALLOCATE),
mPreviousPriority(ANDROID_PRIORITY_NORMAL),
mPreviousSchedulingGroup(SP_DEFAULT),
mProxy(NULL)
{
+ uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(mClientIdentity.uid));
+ pid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(mClientIdentity.pid));
(void)set(inputSource, sampleRate, format, channelMask, frameCount, cbf, user,
notificationFrames, false /*threadCanCallJava*/, sessionId, transferType, flags,
- uid, pid, pAttributes, selectedDeviceId,
- selectedMicDirection, microphoneFieldDimension);
+ uid, pid, pAttributes, selectedDeviceId, selectedMicDirection,
+ microphoneFieldDimension);
}
AudioRecord::~AudioRecord()
@@ -211,7 +203,8 @@
IPCThreadState::self()->flushCommands();
ALOGV("%s(%d): releasing session id %d",
__func__, mPortId, mSessionId);
- AudioSystem::releaseAudioSessionId(mSessionId, mClientPid);
+ pid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(mClientIdentity.pid));
+ AudioSystem::releaseAudioSessionId(mSessionId, pid);
}
}
@@ -237,16 +230,29 @@
{
status_t status = NO_ERROR;
uint32_t channelCount;
- pid_t callingPid;
- pid_t myPid;
// Note mPortId is not valid until the track is created, so omit mPortId in ALOG for set.
ALOGV("%s(): inputSource %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, "
- "notificationFrames %u, sessionId %d, transferType %d, flags %#x, opPackageName %s "
+ "notificationFrames %u, sessionId %d, transferType %d, flags %#x, identity %s"
"uid %d, pid %d",
__func__,
inputSource, sampleRate, format, channelMask, frameCount, notificationFrames,
- sessionId, transferType, flags, String8(mOpPackageName).string(), uid, pid);
+ sessionId, transferType, flags, mClientIdentity.toString().c_str(), uid, pid);
+
+ // TODO b/182392553: refactor or remove
+ pid_t callingPid = IPCThreadState::self()->getCallingPid();
+ pid_t myPid = getpid();
+ pid_t adjPid = pid;
+ if (pid == -1 || (callingPid != myPid)) {
+ adjPid = callingPid;
+ }
+ mClientIdentity.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(adjPid));
+
+ uid_t adjUid = uid;
+ if (uid == -1 || (callingPid != myPid)) {
+ adjUid = IPCThreadState::self()->getCallingUid();
+ }
+ mClientIdentity.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(adjUid));
mTracker.reset(new RecordingActivityTracker());
@@ -341,19 +347,6 @@
mSessionId = sessionId;
ALOGV("%s(): mSessionId %d", __func__, mSessionId);
- callingPid = IPCThreadState::self()->getCallingPid();
- myPid = getpid();
- if (uid == AUDIO_UID_INVALID || (callingPid != myPid)) {
- mClientUid = IPCThreadState::self()->getCallingUid();
- } else {
- mClientUid = uid;
- }
- if (pid == -1 || (callingPid != myPid)) {
- mClientPid = callingPid;
- } else {
- mClientPid = pid;
- }
-
mOrigFlags = mFlags = flags;
mCbf = cbf;
@@ -366,7 +359,7 @@
// create the IAudioRecord
{
AutoMutex lock(mLock);
- status = createRecord_l(0 /*epoch*/, mOpPackageName);
+ status = createRecord_l(0 /*epoch*/);
}
ALOGV("%s(%d): status %d", __func__, mPortId, status);
@@ -387,7 +380,7 @@
mMarkerReached = false;
mNewPosition = 0;
mUpdatePeriod = 0;
- AudioSystem::acquireAudioSessionId(mSessionId, mClientPid, mClientUid);
+ AudioSystem::acquireAudioSessionId(mSessionId, adjPid, adjUid);
mSequence = 1;
mObservedSequence = mSequence;
mInOverrun = false;
@@ -744,7 +737,7 @@
}
// must be called with mLock held
-status_t AudioRecord::createRecord_l(const Modulo<uint32_t> &epoch, const String16& opPackageName)
+status_t AudioRecord::createRecord_l(const Modulo<uint32_t> &epoch)
{
const int64_t beginNs = systemTime();
const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
@@ -797,15 +790,13 @@
input.config.sample_rate = mSampleRate;
input.config.channel_mask = mChannelMask;
input.config.format = mFormat;
- input.clientInfo.clientUid = mClientUid;
- input.clientInfo.clientPid = mClientPid;
+ input.clientInfo.identity = mClientIdentity;
input.clientInfo.clientTid = -1;
if (mFlags & AUDIO_INPUT_FLAG_FAST) {
if (mAudioRecordThread != 0) {
input.clientInfo.clientTid = mAudioRecordThread->getTid();
}
}
- input.opPackageName = opPackageName;
input.riid = mTracker->getRiid();
input.flags = mFlags;
@@ -1437,7 +1428,7 @@
// It will also delete the strong references on previous IAudioRecord and IMemory
Modulo<uint32_t> position(mProxy->getPosition());
mNewPosition = position + mUpdatePeriod;
- result = createRecord_l(position, mOpPackageName);
+ result = createRecord_l(position);
if (result == NO_ERROR) {
if (mActive) {
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 74258a1..f476b7d 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -52,6 +52,7 @@
using aidl_utils::statusTFromBinderStatus;
using binder::Status;
using media::IAudioPolicyService;
+using media::permission::Identity;
// client singleton for AudioFlinger binder interface
Mutex AudioSystem::gLock;
@@ -940,8 +941,7 @@
audio_io_handle_t* output,
audio_session_t session,
audio_stream_type_t* stream,
- pid_t pid,
- uid_t uid,
+ const Identity& identity,
const audio_config_t* config,
audio_output_flags_t flags,
audio_port_handle_t* selectedDeviceId,
@@ -974,8 +974,6 @@
media::AudioAttributesInternal attrAidl = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_attributes_t_AudioAttributesInternal(*attr));
int32_t sessionAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_session_t_int32_t(session));
- int32_t pidAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_pid_t_int32_t(pid));
- int32_t uidAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_uid_t_int32_t(uid));
media::AudioConfig configAidl = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_config_t_AudioConfig(*config));
int32_t flagsAidl = VALUE_OR_RETURN_STATUS(
@@ -986,7 +984,7 @@
media::GetOutputForAttrResponse responseAidl;
RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
- aps->getOutputForAttr(attrAidl, sessionAidl, pidAidl, uidAidl, configAidl, flagsAidl,
+ aps->getOutputForAttr(attrAidl, sessionAidl, identity, configAidl, flagsAidl,
selectedDeviceIdAidl, &responseAidl)));
*output = VALUE_OR_RETURN_STATUS(
@@ -1040,9 +1038,7 @@
audio_io_handle_t* input,
audio_unique_id_t riid,
audio_session_t session,
- pid_t pid,
- uid_t uid,
- const String16& opPackageName,
+ const Identity &identity,
const audio_config_base_t* config,
audio_input_flags_t flags,
audio_port_handle_t* selectedDeviceId,
@@ -1072,10 +1068,6 @@
int32_t inputAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_io_handle_t_int32_t(*input));
int32_t riidAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_unique_id_t_int32_t(riid));
int32_t sessionAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_session_t_int32_t(session));
- int32_t pidAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_pid_t_int32_t(pid));
- int32_t uidAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_uid_t_int32_t(uid));
- std::string opPackageNameAidl = VALUE_OR_RETURN_STATUS(
- legacy2aidl_String16_string(opPackageName));
media::AudioConfigBase configAidl = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_config_base_t_AudioConfigBase(*config));
int32_t flagsAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_input_flags_t_int32_t_mask(flags));
@@ -1085,9 +1077,8 @@
media::GetInputForAttrResponse response;
RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
- aps->getInputForAttr(attrAidl, inputAidl, riidAidl, sessionAidl, pidAidl, uidAidl,
- opPackageNameAidl, configAidl, flagsAidl, selectedDeviceIdAidl,
- &response)));
+ aps->getInputForAttr(attrAidl, inputAidl, riidAidl, sessionAidl, identity,
+ configAidl, flagsAidl, selectedDeviceIdAidl, &response)));
*input = VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_audio_io_handle_t(response.input));
*selectedDeviceId = VALUE_OR_RETURN_STATUS(
@@ -1839,8 +1830,7 @@
status_t AudioSystem::getSurroundFormats(unsigned int* numSurroundFormats,
audio_format_t* surroundFormats,
- bool* surroundFormatsEnabled,
- bool reported) {
+ bool* surroundFormatsEnabled) {
if (numSurroundFormats == nullptr || (*numSurroundFormats != 0 &&
(surroundFormats == nullptr ||
surroundFormatsEnabled == nullptr))) {
@@ -1855,8 +1845,8 @@
std::vector<media::audio::common::AudioFormat> surroundFormatsAidl;
std::vector<bool> surroundFormatsEnabledAidl;
RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
- aps->getSurroundFormats(reported, &numSurroundFormatsAidl,
- &surroundFormatsAidl, &surroundFormatsEnabledAidl)));
+ aps->getSurroundFormats(&numSurroundFormatsAidl, &surroundFormatsAidl,
+ &surroundFormatsEnabledAidl)));
*numSurroundFormats = VALUE_OR_RETURN_STATUS(
convertIntegral<unsigned int>(numSurroundFormatsAidl.value));
@@ -1868,6 +1858,29 @@
return OK;
}
+status_t AudioSystem::getReportedSurroundFormats(unsigned int* numSurroundFormats,
+ audio_format_t* surroundFormats) {
+ if (numSurroundFormats == nullptr || (*numSurroundFormats != 0 && surroundFormats == nullptr)) {
+ return BAD_VALUE;
+ }
+
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+ media::Int numSurroundFormatsAidl;
+ numSurroundFormatsAidl.value =
+ VALUE_OR_RETURN_STATUS(convertIntegral<int32_t>(*numSurroundFormats));
+ std::vector<media::audio::common::AudioFormat> surroundFormatsAidl;
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
+ aps->getReportedSurroundFormats(&numSurroundFormatsAidl, &surroundFormatsAidl)));
+
+ *numSurroundFormats = VALUE_OR_RETURN_STATUS(
+ convertIntegral<unsigned int>(numSurroundFormatsAidl.value));
+ RETURN_STATUS_IF_ERROR(
+ convertRange(surroundFormatsAidl.begin(), surroundFormatsAidl.end(), surroundFormats,
+ aidl2legacy_AudioFormat_audio_format_t));
+ return OK;
+}
+
status_t AudioSystem::setSurroundFormatEnabled(audio_format_t audioFormat, bool enabled) {
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
if (aps == 0) return PERMISSION_DENIED;
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index d2f714a..8788a86 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -38,15 +38,6 @@
#include <media/MediaMetricsItem.h>
#include <media/TypeConverter.h>
-#define VALUE_OR_FATAL(result) \
- ({ \
- auto _tmp = (result); \
- LOG_ALWAYS_FATAL_IF(!_tmp.ok(), \
- "Failed result (%d)", \
- _tmp.error()); \
- std::move(_tmp.value()); \
- })
-
#define WAIT_PERIOD_MS 10
#define WAIT_STREAM_END_TIMEOUT_SEC 120
static const int kMaxLoopCountNotifications = 32;
@@ -57,6 +48,7 @@
// ---------------------------------------------------------------------------
using media::VolumeShaper;
+using media::permission::Identity;
// TODO: Move to a separate .h
@@ -233,11 +225,11 @@
return NO_ERROR;
}
-AudioTrack::AudioTrack() : AudioTrack("" /*opPackageName*/)
+AudioTrack::AudioTrack() : AudioTrack(Identity())
{
}
-AudioTrack::AudioTrack(const std::string& opPackageName)
+AudioTrack::AudioTrack(const Identity& identity)
: mStatus(NO_INIT),
mState(STATE_STOPPED),
mPreviousPriority(ANDROID_PRIORITY_NORMAL),
@@ -245,7 +237,7 @@
mPausedPosition(0),
mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE),
- mOpPackageName(opPackageName),
+ mClientIdentity(identity),
mAudioTrackCallback(new AudioTrackCallback())
{
mAttributes.content_type = AUDIO_CONTENT_TYPE_UNKNOWN;
@@ -267,19 +259,16 @@
audio_session_t sessionId,
transfer_type transferType,
const audio_offload_info_t *offloadInfo,
- uid_t uid,
- pid_t pid,
+ const Identity& identity,
const audio_attributes_t* pAttributes,
bool doNotReconnect,
float maxRequiredSpeed,
- audio_port_handle_t selectedDeviceId,
- const std::string& opPackageName)
+ audio_port_handle_t selectedDeviceId)
: mStatus(NO_INIT),
mState(STATE_STOPPED),
mPreviousPriority(ANDROID_PRIORITY_NORMAL),
mPreviousSchedulingGroup(SP_DEFAULT),
mPausedPosition(0),
- mOpPackageName(opPackageName),
mAudioTrackCallback(new AudioTrackCallback())
{
mAttributes = AUDIO_ATTRIBUTES_INITIALIZER;
@@ -287,7 +276,7 @@
(void)set(streamType, sampleRate, format, channelMask,
frameCount, flags, cbf, user, notificationFrames,
0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId, transferType,
- offloadInfo, uid, pid, pAttributes, doNotReconnect, maxRequiredSpeed, selectedDeviceId);
+ offloadInfo, identity, pAttributes, doNotReconnect, maxRequiredSpeed, selectedDeviceId);
}
AudioTrack::AudioTrack(
@@ -303,19 +292,16 @@
audio_session_t sessionId,
transfer_type transferType,
const audio_offload_info_t *offloadInfo,
- uid_t uid,
- pid_t pid,
+ const Identity& identity,
const audio_attributes_t* pAttributes,
bool doNotReconnect,
- float maxRequiredSpeed,
- const std::string& opPackageName)
+ float maxRequiredSpeed)
: mStatus(NO_INIT),
mState(STATE_STOPPED),
mPreviousPriority(ANDROID_PRIORITY_NORMAL),
mPreviousSchedulingGroup(SP_DEFAULT),
mPausedPosition(0),
mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
- mOpPackageName(opPackageName),
mAudioTrackCallback(new AudioTrackCallback())
{
mAttributes = AUDIO_ATTRIBUTES_INITIALIZER;
@@ -323,7 +309,7 @@
(void)set(streamType, sampleRate, format, channelMask,
0 /*frameCount*/, flags, cbf, user, notificationFrames,
sharedBuffer, false /*threadCanCallJava*/, sessionId, transferType, offloadInfo,
- uid, pid, pAttributes, doNotReconnect, maxRequiredSpeed);
+ identity, pAttributes, doNotReconnect, maxRequiredSpeed);
}
AudioTrack::~AudioTrack()
@@ -361,10 +347,11 @@
mCblkMemory.clear();
mSharedBuffer.clear();
IPCThreadState::self()->flushCommands();
+ pid_t clientPid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(mClientIdentity.pid));
ALOGV("%s(%d), releasing session id %d from %d on behalf of %d",
__func__, mPortId,
- mSessionId, IPCThreadState::self()->getCallingPid(), mClientPid);
- AudioSystem::releaseAudioSessionId(mSessionId, mClientPid);
+ mSessionId, IPCThreadState::self()->getCallingPid(), clientPid);
+ AudioSystem::releaseAudioSessionId(mSessionId, clientPid);
}
}
@@ -383,8 +370,7 @@
audio_session_t sessionId,
transfer_type transferType,
const audio_offload_info_t *offloadInfo,
- uid_t uid,
- pid_t pid,
+ const Identity& identity,
const audio_attributes_t* pAttributes,
bool doNotReconnect,
float maxRequiredSpeed,
@@ -394,13 +380,15 @@
uint32_t channelCount;
pid_t callingPid;
pid_t myPid;
+ uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.uid));
+ pid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(identity.pid));
// Note mPortId is not valid until the track is created, so omit mPortId in ALOG for set.
ALOGV("%s(): streamType %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, "
"flags #%x, notificationFrames %d, sessionId %d, transferType %d, uid %d, pid %d",
__func__,
streamType, sampleRate, format, channelMask, frameCount, flags, notificationFrames,
- sessionId, transferType, uid, pid);
+ sessionId, transferType, identity.uid, identity.pid);
mThreadCanCallJava = threadCanCallJava;
mSelectedDeviceId = selectedDeviceId;
@@ -596,17 +584,19 @@
notificationFrames, minNotificationsPerBuffer, maxNotificationsPerBuffer);
}
mNotificationFramesAct = 0;
+ // TODO b/182392553: refactor or remove
callingPid = IPCThreadState::self()->getCallingPid();
myPid = getpid();
- if (uid == AUDIO_UID_INVALID || (callingPid != myPid)) {
- mClientUid = IPCThreadState::self()->getCallingUid();
+ if (uid == -1 || (callingPid != myPid)) {
+ mClientIdentity.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(
+ IPCThreadState::self()->getCallingUid()));
} else {
- mClientUid = uid;
+ mClientIdentity.uid = identity.uid;
}
- if (pid == -1 || (callingPid != myPid)) {
- mClientPid = callingPid;
+ if (pid == (pid_t)-1 || (callingPid != myPid)) {
+ mClientIdentity.pid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(callingPid));
} else {
- mClientPid = pid;
+ mClientIdentity.pid = identity.pid;
}
mAuxEffectId = 0;
mOrigFlags = mFlags = flags;
@@ -645,7 +635,7 @@
mReleased = 0;
mStartNs = 0;
mStartFromZeroUs = 0;
- AudioSystem::acquireAudioSessionId(mSessionId, mClientPid, mClientUid);
+ AudioSystem::acquireAudioSessionId(mSessionId, pid, uid);
mSequence = 1;
mObservedSequence = mSequence;
mInUnderrun = false;
@@ -691,10 +681,13 @@
float maxRequiredSpeed,
audio_port_handle_t selectedDeviceId)
{
+ Identity identity;
+ identity.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(uid));
+ identity.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(pid));
return set(streamType, sampleRate, format,
static_cast<audio_channel_mask_t>(channelMask),
frameCount, flags, cbf, user, notificationFrames, sharedBuffer,
- threadCanCallJava, sessionId, transferType, offloadInfo, uid, pid,
+ threadCanCallJava, sessionId, transferType, offloadInfo, identity,
pAttributes, doNotReconnect, maxRequiredSpeed, selectedDeviceId);
}
@@ -1656,8 +1649,7 @@
input.config.channel_mask = mChannelMask;
input.config.format = mFormat;
input.config.offload_info = mOffloadInfoCopy;
- input.clientInfo.clientUid = mClientUid;
- input.clientInfo.clientPid = mClientPid;
+ input.clientInfo.identity = mClientIdentity;
input.clientInfo.clientTid = -1;
if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
// It is currently meaningless to request SCHED_FIFO for a Java thread. Even if the
@@ -1681,7 +1673,6 @@
input.selectedDeviceId = mSelectedDeviceId;
input.sessionId = mSessionId;
input.audioTrackCallback = mAudioTrackCallback;
- input.opPackageName = mOpPackageName;
media::CreateTrackResponse response;
status = audioFlinger->createTrack(VALUE_OR_FATAL(input.toAidl()), response);
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index 20124df..4103630 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -61,7 +61,6 @@
aidl.notificationsPerBuffer = VALUE_OR_RETURN(convertIntegral<int32_t>(notificationsPerBuffer));
aidl.speed = speed;
aidl.audioTrackCallback = audioTrackCallback;
- aidl.opPackageName = opPackageName;
aidl.flags = VALUE_OR_RETURN(legacy2aidl_audio_output_flags_t_int32_t_mask(flags));
aidl.frameCount = VALUE_OR_RETURN(convertIntegral<int64_t>(frameCount));
aidl.notificationFrameCount = VALUE_OR_RETURN(convertIntegral<int64_t>(notificationFrameCount));
@@ -82,7 +81,6 @@
convertIntegral<uint32_t>(aidl.notificationsPerBuffer));
legacy.speed = aidl.speed;
legacy.audioTrackCallback = aidl.audioTrackCallback;
- legacy.opPackageName = aidl.opPackageName;
legacy.flags = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_output_flags_t_mask(aidl.flags));
legacy.frameCount = VALUE_OR_RETURN(convertIntegral<size_t>(aidl.frameCount));
legacy.notificationFrameCount = VALUE_OR_RETURN(
@@ -139,7 +137,6 @@
aidl.attr = VALUE_OR_RETURN(legacy2aidl_audio_attributes_t_AudioAttributesInternal(attr));
aidl.config = VALUE_OR_RETURN(legacy2aidl_audio_config_base_t_AudioConfigBase(config));
aidl.clientInfo = VALUE_OR_RETURN(legacy2aidl_AudioClient_AudioClient(clientInfo));
- aidl.opPackageName = VALUE_OR_RETURN(legacy2aidl_String16_string(opPackageName));
aidl.riid = VALUE_OR_RETURN(legacy2aidl_audio_unique_id_t_int32_t(riid));
aidl.flags = VALUE_OR_RETURN(legacy2aidl_audio_input_flags_t_int32_t_mask(flags));
aidl.frameCount = VALUE_OR_RETURN(convertIntegral<int64_t>(frameCount));
@@ -157,7 +154,6 @@
legacy.attr = VALUE_OR_RETURN(aidl2legacy_AudioAttributesInternal_audio_attributes_t(aidl.attr));
legacy.config = VALUE_OR_RETURN(aidl2legacy_AudioConfigBase_audio_config_base_t(aidl.config));
legacy.clientInfo = VALUE_OR_RETURN(aidl2legacy_AudioClient_AudioClient(aidl.clientInfo));
- legacy.opPackageName = VALUE_OR_RETURN(aidl2legacy_string_view_String16(aidl.opPackageName));
legacy.riid = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_unique_id_t(aidl.riid));
legacy.flags = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_input_flags_t_mask(aidl.flags));
legacy.frameCount = VALUE_OR_RETURN(convertIntegral<size_t>(aidl.frameCount));
diff --git a/media/libaudioclient/ToneGenerator.cpp b/media/libaudioclient/ToneGenerator.cpp
index c9f3ab9..451c4b1 100644
--- a/media/libaudioclient/ToneGenerator.cpp
+++ b/media/libaudioclient/ToneGenerator.cpp
@@ -27,6 +27,7 @@
namespace android {
+using media::permission::Identity;
// Descriptors for all available tones (See ToneGenerator::ToneDescriptor class declaration for details)
const ToneGenerator::ToneDescriptor ToneGenerator::sToneDescriptors[] = {
@@ -1259,7 +1260,10 @@
////////////////////////////////////////////////////////////////////////////////
bool ToneGenerator::initAudioTrack() {
// Open audio track in mono, PCM 16bit, default sampling rate.
- mpAudioTrack = new AudioTrack(mOpPackageName);
+ // TODO b/182392769: use identity util
+ Identity identity = Identity();
+ identity.packageName = mOpPackageName;
+ mpAudioTrack = new AudioTrack(identity);
ALOGV("AudioTrack(%p) created", mpAudioTrack.get());
audio_attributes_t attr;
@@ -1285,8 +1289,7 @@
AUDIO_SESSION_ALLOCATE,
AudioTrack::TRANSFER_CALLBACK,
nullptr,
- AUDIO_UID_INVALID,
- -1,
+ identity,
&attr);
// Set caller name so it can be logged in destructor.
// MediaMetricsConstants.h: AMEDIAMETRICS_PROP_CALLERNAME_VALUE_TONEGENERATOR
diff --git a/media/libaudioclient/aidl/android/media/AudioClient.aidl b/media/libaudioclient/aidl/android/media/AudioClient.aidl
index 7bff0d6..aa4d8f5 100644
--- a/media/libaudioclient/aidl/android/media/AudioClient.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioClient.aidl
@@ -16,15 +16,13 @@
package android.media;
+import android.media.permission.Identity;
+
/**
* {@hide}
*/
parcelable AudioClient {
- /** Interpreted as uid_t. */
- int clientUid;
- /** Interpreted as pid_t. */
- int clientPid;
/** Interpreted as pid_t. */
int clientTid;
- @utf8InCpp String packageName;
+ Identity identity;
}
diff --git a/media/libaudioclient/aidl/android/media/CreateEffectRequest.aidl b/media/libaudioclient/aidl/android/media/CreateEffectRequest.aidl
index 8368854..5737fcd 100644
--- a/media/libaudioclient/aidl/android/media/CreateEffectRequest.aidl
+++ b/media/libaudioclient/aidl/android/media/CreateEffectRequest.aidl
@@ -19,6 +19,7 @@
import android.media.AudioDevice;
import android.media.EffectDescriptor;
import android.media.IEffectClient;
+import android.media.permission.Identity;
/**
* Input arguments of the createEffect() method.
@@ -34,8 +35,6 @@
/** Interpreted as audio_session_t. */
int sessionId;
AudioDevice device;
- @utf8InCpp String opPackageName;
- /** Interpreted as pid_t. */
- int pid;
+ Identity identity;
boolean probe;
}
diff --git a/media/libaudioclient/aidl/android/media/CreateRecordRequest.aidl b/media/libaudioclient/aidl/android/media/CreateRecordRequest.aidl
index 6da743a..62007da 100644
--- a/media/libaudioclient/aidl/android/media/CreateRecordRequest.aidl
+++ b/media/libaudioclient/aidl/android/media/CreateRecordRequest.aidl
@@ -19,6 +19,7 @@
import android.media.AudioAttributesInternal;
import android.media.AudioClient;
import android.media.AudioConfigBase;
+import android.media.permission.Identity;
/**
* CreateRecordRequest contains all input arguments sent by AudioRecord to AudioFlinger
@@ -31,7 +32,6 @@
AudioAttributesInternal attr;
AudioConfigBase config;
AudioClient clientInfo;
- @utf8InCpp String opPackageName;
/** Interpreted as audio_unique_id_t. */
int riid;
/** Bitmask, indexed by AudioInputFlags. */
diff --git a/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl b/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
index 89fad5a..f8924f3 100644
--- a/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
@@ -48,6 +48,7 @@
import android.media.IAudioPolicyServiceClient;
import android.media.ICaptureStateListener;
import android.media.Int;
+import android.media.permission.Identity;
import android.media.SoundTriggerSession;
/**
@@ -80,8 +81,7 @@
GetOutputForAttrResponse getOutputForAttr(in AudioAttributesInternal attr,
int /* audio_session_t */ session,
- int /* pid_t */ pid,
- int /* uid_t */ uid,
+ in Identity identity,
in AudioConfig config,
int /* Bitmask, indexed by AudioOutputFlags */ flags,
int /* audio_port_handle_t */ selectedDeviceId);
@@ -96,9 +96,7 @@
int /* audio_io_handle_t */ input,
int /* audio_unique_id_t */ riid,
int /* audio_session_t */ session,
- int /* pid_t */ pid,
- int /* uid_t */ uid,
- @utf8InCpp String opPackageName,
+ in Identity identity,
in AudioConfigBase config,
int /* Bitmask, indexed by AudioInputFlags */ flags,
int /* audio_port_handle_t */ selectedDeviceId);
@@ -279,11 +277,21 @@
* Passing '0' on input and inspecting the value on output is a common way of determining the
* number of elements without actually retrieving them.
*/
- void getSurroundFormats(boolean reported,
- inout Int count,
+ void getSurroundFormats(inout Int count,
out AudioFormat[] formats,
out boolean[] formatsEnabled);
+ /**
+ * Populates the surround formats reported by the HDMI devices in formats.
+ *
+ * On input, count represents the maximum length of the returned array.
+ * On output, count is the total number of elements, which may be larger than the array size.
+ * Passing '0' on input and inspecting the value on output is a common way of determining the
+ * number of elements without actually retrieving them.
+ */
+ void getReportedSurroundFormats(inout Int count,
+ out AudioFormat[] formats);
+
AudioFormat[] getHwOffloadEncodingFormatsSupportedForA2DP();
void setSurroundFormatEnabled(AudioFormat audioFormat, boolean enabled);
diff --git a/media/libaudioclient/fuzzer/Android.bp b/media/libaudioclient/fuzzer/Android.bp
index 18a3704..21e25b9 100644
--- a/media/libaudioclient/fuzzer/Android.bp
+++ b/media/libaudioclient/fuzzer/Android.bp
@@ -65,6 +65,7 @@
"libutils",
"libxml2",
"mediametricsservice-aidl-cpp",
+ "media_permission-aidl-cpp",
],
header_libs: [
"libaudiofoundation_headers",
diff --git a/media/libaudioclient/fuzzer/audioflinger_fuzzer.cpp b/media/libaudioclient/fuzzer/audioflinger_fuzzer.cpp
index db2b0b8..1b75917 100644
--- a/media/libaudioclient/fuzzer/audioflinger_fuzzer.cpp
+++ b/media/libaudioclient/fuzzer/audioflinger_fuzzer.cpp
@@ -23,8 +23,10 @@
*/
#include <android_audio_policy_configuration_V7_0-enums.h>
+#include <android/media/permission/Identity.h>
#include <binder/IServiceManager.h>
#include <binder/MemoryDealer.h>
+#include <media/AidlConversion.h>
#include <media/AudioEffect.h>
#include <media/AudioRecord.h>
#include <media/AudioSystem.h>
@@ -35,6 +37,10 @@
#define MAX_STRING_LENGTH 256
#define MAX_ARRAY_LENGTH 256
+constexpr int32_t kMinSampleRateHz = 4000;
+constexpr int32_t kMaxSampleRateHz = 192000;
+constexpr int32_t kSampleRateUnspecified = 0;
+
using namespace std;
using namespace android;
@@ -42,6 +48,8 @@
using namespace ::android::audio::policy::configuration::V7_0;
}
+using media::permission::Identity;
+
constexpr audio_unique_id_use_t kUniqueIds[] = {
AUDIO_UNIQUE_ID_USE_UNSPECIFIED, AUDIO_UNIQUE_ID_USE_SESSION, AUDIO_UNIQUE_ID_USE_MODULE,
AUDIO_UNIQUE_ID_USE_EFFECT, AUDIO_UNIQUE_ID_USE_PATCH, AUDIO_UNIQUE_ID_USE_OUTPUT,
@@ -130,29 +138,20 @@
xsdc_enum_range<xsd::AudioInOutFlag>{}, audio_output_flag_from_string, "_OUTPUT_");
template <typename T, size_t size>
-T getValueFromArray(FuzzedDataProvider *fdp, const T (&arr)[size]) {
- return arr[fdp->ConsumeIntegralInRange<int32_t>(0, size - 1)];
-}
-
-template <typename T, size_t size>
T getValue(FuzzedDataProvider *fdp, const T (&arr)[size]) {
- if (fdp->ConsumeBool()) {
- return static_cast<T>(fdp->ConsumeIntegral<int32_t>());
- }
- return getValueFromArray(fdp, arr);
-}
-
-template <typename T>
-T getValueFromVector(FuzzedDataProvider *fdp, std::vector<T> vec) {
- return vec[fdp->ConsumeIntegralInRange<int32_t>(0, vec.size() - 1)];
+ return arr[fdp->ConsumeIntegralInRange<int32_t>(0, size - 1)];
}
template <typename T>
T getValue(FuzzedDataProvider *fdp, std::vector<T> vec) {
+ return vec[fdp->ConsumeIntegralInRange<int32_t>(0, vec.size() - 1)];
+}
+
+int32_t getSampleRate(FuzzedDataProvider *fdp) {
if (fdp->ConsumeBool()) {
- return static_cast<T>(fdp->ConsumeIntegral<int32_t>());
+ return fdp->ConsumeIntegralInRange<int32_t>(kMinSampleRateHz, kMaxSampleRateHz);
}
- return getValueFromVector(fdp, vec);
+ return kSampleRateUnspecified;
}
class DeathNotifier : public IBinder::DeathRecipient {
@@ -189,7 +188,7 @@
}
void AudioFlingerFuzzer::invokeAudioTrack() {
- uint32_t sampleRate = mFdp.ConsumeIntegral<uint32_t>();
+ uint32_t sampleRate = getSampleRate(&mFdp);
audio_format_t format = getValue(&mFdp, kFormats);
audio_channel_mask_t channelMask = getValue(&mFdp, kChannelMasks);
size_t frameCount = static_cast<size_t>(mFdp.ConsumeIntegral<uint32_t>());
@@ -226,11 +225,15 @@
attributes.usage = usage;
sp<AudioTrack> track = new AudioTrack();
+ // TODO b/182392769: use identity util
+ Identity i;
+ i.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(getuid()));
+ i.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(getpid()));
track->set(AUDIO_STREAM_DEFAULT, sampleRate, format, channelMask, frameCount, flags, nullptr,
nullptr, notificationFrames, sharedBuffer, false, sessionId,
((fast && sharedBuffer == 0) || offload) ? AudioTrack::TRANSFER_CALLBACK
: AudioTrack::TRANSFER_DEFAULT,
- offload ? &offloadInfo : nullptr, getuid(), getpid(), &attributes, false, 1.0f,
+ offload ? &offloadInfo : nullptr, i, &attributes, false, 1.0f,
AUDIO_PORT_HANDLE_NONE);
status_t status = track->initCheck();
@@ -259,7 +262,7 @@
float auxEffectSendLevel;
track->getAuxEffectSendLevel(&auxEffectSendLevel);
- track->setSampleRate(mFdp.ConsumeIntegral<uint32_t>());
+ track->setSampleRate(getSampleRate(&mFdp));
track->getSampleRate();
track->getOriginalSampleRate();
@@ -292,7 +295,7 @@
void AudioFlingerFuzzer::invokeAudioRecord() {
int32_t notificationFrames = mFdp.ConsumeIntegral<int32_t>();
- uint32_t sampleRate = mFdp.ConsumeIntegral<uint32_t>();
+ uint32_t sampleRate = getSampleRate(&mFdp);
size_t frameCount = static_cast<size_t>(mFdp.ConsumeIntegral<uint32_t>());
audio_format_t format = getValue(&mFdp, kFormats);
audio_channel_mask_t channelMask = getValue(&mFdp, kChannelMasks);
@@ -305,7 +308,10 @@
attributes.source = inputSource;
- sp<AudioRecord> record = new AudioRecord(String16(mFdp.ConsumeRandomLengthString().c_str()));
+ // TODO b/182392769: use identity util
+ Identity i;
+ i.packageName = std::string(mFdp.ConsumeRandomLengthString().c_str());
+ sp<AudioRecord> record = new AudioRecord(i);
record->set(AUDIO_SOURCE_DEFAULT, sampleRate, format, channelMask, frameCount, nullptr, nullptr,
notificationFrames, false, sessionId,
fast ? AudioRecord::TRANSFER_CALLBACK : AudioRecord::TRANSFER_DEFAULT, flags,
@@ -396,7 +402,7 @@
const int32_t priority = mFdp.ConsumeIntegral<int32_t>();
audio_session_t sessionId = static_cast<audio_session_t>(mFdp.ConsumeIntegral<int32_t>());
const audio_io_handle_t io = mFdp.ConsumeIntegral<int32_t>();
- String16 opPackageName = static_cast<String16>(mFdp.ConsumeRandomLengthString().c_str());
+ std::string opPackageName = static_cast<std::string>(mFdp.ConsumeRandomLengthString().c_str());
AudioDeviceTypeAddr device;
sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
@@ -412,8 +418,9 @@
request.output = io;
request.sessionId = sessionId;
request.device = VALUE_OR_RETURN_STATUS(legacy2aidl_AudioDeviceTypeAddress(device));
- request.opPackageName = VALUE_OR_RETURN_STATUS(legacy2aidl_String16_string(opPackageName));
- request.pid = getpid();
+ // TODO b/182392769: use identity util
+ request.identity.packageName = opPackageName;
+ request.identity.pid = VALUE_OR_RETURN_STATUS(legacy2aidl_pid_t_int32_t(getpid()));
request.probe = false;
media::CreateEffectResponse response{};
@@ -518,7 +525,7 @@
AudioSystem::getFrameCountHAL(mFdp.ConsumeIntegral<int32_t>(), &frameCount);
size_t buffSize;
- uint32_t sampleRate = mFdp.ConsumeIntegral<uint32_t>();
+ uint32_t sampleRate = getSampleRate(&mFdp);
audio_format_t format = getValue(&mFdp, kFormats);
audio_channel_mask_t channelMask = getValue(&mFdp, kChannelMasks);
AudioSystem::getInputBufferSize(sampleRate, format, channelMask, &buffSize);
@@ -572,12 +579,12 @@
config.offload_info.format = getValue(&mFdp, kFormats);
config.offload_info.has_video = mFdp.ConsumeBool();
config.offload_info.is_streaming = mFdp.ConsumeBool();
- config.offload_info.sample_rate = (mFdp.ConsumeIntegral<uint32_t>());
+ config.offload_info.sample_rate = getSampleRate(&mFdp);
config.offload_info.sync_id = mFdp.ConsumeIntegral<uint32_t>();
config.offload_info.stream_type = getValue(&mFdp, kStreamtypes);
config.offload_info.usage = getValue(&mFdp, kUsages);
- config.sample_rate = mFdp.ConsumeIntegral<uint32_t>();
+ config.sample_rate = getSampleRate(&mFdp);
audio_devices_t device = getValue(&mFdp, kDevices);
audio_source_t source = getValue(&mFdp, kInputSources);
@@ -628,13 +635,13 @@
config.offload_info.format = getValue(&mFdp, kFormats);
config.offload_info.has_video = mFdp.ConsumeBool();
config.offload_info.is_streaming = mFdp.ConsumeBool();
- config.offload_info.sample_rate = mFdp.ConsumeIntegral<uint32_t>();
+ config.offload_info.sample_rate = getSampleRate(&mFdp);
config.offload_info.stream_type = getValue(&mFdp, kStreamtypes);
config.offload_info.sync_id = mFdp.ConsumeIntegral<uint32_t>();
config.offload_info.usage = getValue(&mFdp, kUsages);
config.format = getValue(&mFdp, kFormats);
- config.sample_rate = mFdp.ConsumeIntegral<uint32_t>();
+ config.sample_rate = getSampleRate(&mFdp);
sp<DeviceDescriptorBase> device = new DeviceDescriptorBase(getValue(&mFdp, kDevices));
audio_output_flags_t flags = getValue(&mFdp, kOutputFlags);
@@ -683,7 +690,7 @@
patch.sources[i].gain.ramp_duration_ms = mFdp.ConsumeIntegral<uint32_t>();
patch.sources[i].id = static_cast<audio_format_t>(mFdp.ConsumeIntegral<int32_t>());
patch.sources[i].role = getValue(&mFdp, kPortRoles);
- patch.sources[i].sample_rate = mFdp.ConsumeIntegral<uint32_t>();
+ patch.sources[i].sample_rate = getSampleRate(&mFdp);
patch.sources[i].type = getValue(&mFdp, kPortTypes);
patch.sinks[i].config_mask = mFdp.ConsumeIntegral<uint32_t>();
@@ -695,7 +702,7 @@
patch.sinks[i].gain.ramp_duration_ms = mFdp.ConsumeIntegral<uint32_t>();
patch.sinks[i].id = static_cast<audio_format_t>(mFdp.ConsumeIntegral<int32_t>());
patch.sinks[i].role = getValue(&mFdp, kPortRoles);
- patch.sinks[i].sample_rate = mFdp.ConsumeIntegral<uint32_t>();
+ patch.sinks[i].sample_rate = getSampleRate(&mFdp);
patch.sinks[i].type = getValue(&mFdp, kPortTypes);
}
diff --git a/media/libaudioclient/include/media/AidlConversion.h b/media/libaudioclient/include/media/AidlConversion.h
index bde20cd..fd87dc2 100644
--- a/media/libaudioclient/include/media/AidlConversion.h
+++ b/media/libaudioclient/include/media/AidlConversion.h
@@ -108,6 +108,11 @@
ConversionResult<String16> aidl2legacy_string_view_String16(std::string_view aidl);
ConversionResult<std::string> legacy2aidl_String16_string(const String16& legacy);
+ConversionResult<std::optional<String16>>
+aidl2legacy_optional_string_view_optional_String16(std::optional<std::string_view> aidl);
+ConversionResult<std::optional<std::string_view>>
+legacy2aidl_optional_String16_optional_string(std::optional<String16> legacy);
+
ConversionResult<audio_io_config_event> aidl2legacy_AudioIoConfigEvent_audio_io_config_event(
media::AudioIoConfigEvent aidl);
ConversionResult<media::AudioIoConfigEvent> legacy2aidl_audio_io_config_event_AudioIoConfigEvent(
diff --git a/media/libaudioclient/include/media/AidlConversionUtil.h b/media/libaudioclient/include/media/AidlConversionUtil.h
index bf2d800..c1a2be3 100644
--- a/media/libaudioclient/include/media/AidlConversionUtil.h
+++ b/media/libaudioclient/include/media/AidlConversionUtil.h
@@ -48,6 +48,15 @@
std::move(_tmp.value()); \
})
+#define VALUE_OR_FATAL(result) \
+ ({ \
+ auto _tmp = (result); \
+ LOG_ALWAYS_FATAL_IF(!_tmp.ok(), \
+ "Function: %s Line: %d Failed result (%d)",\
+ __FUNCTION__, __LINE__, _tmp.error()); \
+ std::move(_tmp.value()); \
+ })
+
/**
* A generic template to safely cast between integral types, respecting limits of the destination
* type.
diff --git a/media/libaudioclient/include/media/AudioClient.h b/media/libaudioclient/include/media/AudioClient.h
index 0b89d15..295fd4f 100644
--- a/media/libaudioclient/include/media/AudioClient.h
+++ b/media/libaudioclient/include/media/AudioClient.h
@@ -19,19 +19,17 @@
#define ANDROID_AUDIO_CLIENT_H
#include <sys/types.h>
-#include <utils/String16.h>
+#include <android/media/permission/Identity.h>
namespace android {
class AudioClient {
public:
AudioClient() :
- clientUid(-1), clientPid(-1), clientTid(-1), packageName("") {}
+ clientTid(-1) {}
- uid_t clientUid;
- pid_t clientPid;
pid_t clientTid;
- String16 packageName;
+ android::media::permission::Identity identity;
};
}; // namespace android
diff --git a/media/libaudioclient/include/media/AudioEffect.h b/media/libaudioclient/include/media/AudioEffect.h
index 0d18fb1..974ce62 100644
--- a/media/libaudioclient/include/media/AudioEffect.h
+++ b/media/libaudioclient/include/media/AudioEffect.h
@@ -23,6 +23,7 @@
#include <media/IAudioFlinger.h>
#include <media/AudioSystem.h>
#include <system/audio_effect.h>
+#include <android/media/permission/Identity.h>
#include <utils/RefBase.h>
#include <utils/Errors.h>
@@ -31,7 +32,6 @@
#include "android/media/IEffect.h"
#include "android/media/BnEffectClient.h"
-
namespace android {
// ----------------------------------------------------------------------------
@@ -337,9 +337,9 @@
*
* Parameters:
*
- * opPackageName: The package name used for app op checks.
+ * client: Identity for app-op checks
*/
- explicit AudioEffect(const String16& opPackageName);
+ explicit AudioEffect(const media::permission::Identity& client);
/* Terminates the AudioEffect and unregisters it from AudioFlinger.
* The effect engine is also destroyed if this AudioEffect was the last controlling
@@ -531,7 +531,7 @@
static const uint32_t kMaxPreProcessing = 10;
protected:
- const String16 mOpPackageName; // The package name used for app op checks.
+ media::permission::Identity mClientIdentity; // Identity used for app op checks.
bool mEnabled = false; // enable state
audio_session_t mSessionId = AUDIO_SESSION_OUTPUT_MIX; // audio session ID
int32_t mPriority = 0; // priority for effect control
@@ -606,8 +606,6 @@
sp<EffectClient> mIEffectClient; // IEffectClient implementation
sp<IMemory> mCblkMemory; // shared memory for deferred parameter setting
effect_param_cblk_t* mCblk = nullptr; // control block for deferred parameter setting
- pid_t mClientPid = (pid_t)-1;
- uid_t mClientUid = (uid_t)-1;
};
diff --git a/media/libaudioclient/include/media/AudioRecord.h b/media/libaudioclient/include/media/AudioRecord.h
index d70d91e..82a29d4 100644
--- a/media/libaudioclient/include/media/AudioRecord.h
+++ b/media/libaudioclient/include/media/AudioRecord.h
@@ -32,6 +32,7 @@
#include <utils/threads.h>
#include "android/media/IAudioRecord.h"
+#include <android/media/permission/Identity.h>
namespace android {
@@ -148,9 +149,9 @@
*
* Parameters:
*
- * opPackageName: The package name used for app ops.
+ * clientIdentity: The identity of the owner of the record
*/
- AudioRecord(const String16& opPackageName);
+ AudioRecord(const media::permission::Identity& clientIdentity);
/* Creates an AudioRecord object and registers it with AudioFlinger.
* Once created, the track needs to be started before it can be used.
@@ -163,7 +164,7 @@
* format: Audio format (e.g AUDIO_FORMAT_PCM_16_BIT for signed
* 16 bits per sample).
* channelMask: Channel mask, such that audio_is_input_channel(channelMask) is true.
- * opPackageName: The package name used for app ops.
+ * client: The identity of the owner of the record
* frameCount: Minimum size of track PCM buffer in frames. This defines the
* application's contribution to the
* latency of the track. The actual size selected by the AudioRecord could
@@ -186,7 +187,7 @@
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
- const String16& opPackageName,
+ const media::permission::Identity& clientIdentity,
size_t frameCount = 0,
callback_t cbf = NULL,
void* user = NULL,
@@ -194,8 +195,6 @@
audio_session_t sessionId = AUDIO_SESSION_ALLOCATE,
transfer_type transferType = TRANSFER_DEFAULT,
audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE,
- uid_t uid = AUDIO_UID_INVALID,
- pid_t pid = -1,
const audio_attributes_t* pAttributes = NULL,
audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE,
audio_microphone_direction_t
@@ -638,7 +637,7 @@
// caller must hold lock on mLock for all _l methods
- status_t createRecord_l(const Modulo<uint32_t> &epoch, const String16& opPackageName);
+ status_t createRecord_l(const Modulo<uint32_t> &epoch);
// FIXME enum is faster than strcmp() for parameter 'from'
status_t restoreRecord_l(const char *from);
@@ -679,7 +678,7 @@
status_t mStatus;
- String16 mOpPackageName; // The package name used for app ops.
+ media::permission::Identity mClientIdentity; // The identity of the owner of this record
size_t mFrameCount; // corresponds to current IAudioRecord, value is
// reported back by AudioFlinger to the client
@@ -754,8 +753,6 @@
sp<DeathNotifier> mDeathNotifier;
uint32_t mSequence; // incremented for each new IAudioRecord attempt
- uid_t mClientUid;
- pid_t mClientPid;
audio_attributes_t mAttributes;
// For Device Selection API
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 694f2d0..c63d29f 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -19,6 +19,7 @@
#include <sys/types.h>
+#include <android/media/permission/Identity.h>
#include <android/media/BnAudioFlingerClient.h>
#include <android/media/BnAudioPolicyServiceClient.h>
#include <media/AidlConversionUtil.h>
@@ -262,8 +263,7 @@
audio_io_handle_t *output,
audio_session_t session,
audio_stream_type_t *stream,
- pid_t pid,
- uid_t uid,
+ const media::permission::Identity& identity,
const audio_config_t *config,
audio_output_flags_t flags,
audio_port_handle_t *selectedDeviceId,
@@ -279,9 +279,7 @@
audio_io_handle_t *input,
audio_unique_id_t riid,
audio_session_t session,
- pid_t pid,
- uid_t uid,
- const String16& opPackageName,
+ const media::permission::Identity& identity,
const audio_config_base_t *config,
audio_input_flags_t flags,
audio_port_handle_t *selectedDeviceId,
@@ -417,8 +415,9 @@
// populated. The actual number of surround formats should be returned at numSurroundFormats.
static status_t getSurroundFormats(unsigned int *numSurroundFormats,
audio_format_t *surroundFormats,
- bool *surroundFormatsEnabled,
- bool reported);
+ bool *surroundFormatsEnabled);
+ static status_t getReportedSurroundFormats(unsigned int *numSurroundFormats,
+ audio_format_t *surroundFormats);
static status_t setSurroundFormatEnabled(audio_format_t audioFormat, bool enabled);
static status_t setAssistantUid(uid_t uid);
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index 2609ec1..b1650ed 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -26,6 +26,7 @@
#include <media/Modulo.h>
#include <media/VolumeShaper.h>
#include <utils/threads.h>
+#include <android/media/permission/Identity.h>
#include <string>
@@ -181,7 +182,7 @@
*/
AudioTrack();
- AudioTrack(const std::string& opPackageName);
+ AudioTrack(const media::permission::Identity& identity);
/* Creates an AudioTrack object and registers it with AudioFlinger.
* Once created, the track needs to be started before it can be used.
@@ -229,10 +230,9 @@
* transferType: How data is transferred to AudioTrack.
* offloadInfo: If not NULL, provides offload parameters for
* AudioSystem::getOutputForAttr().
- * uid: User ID of the app which initially requested this AudioTrack
- * for power management tracking, or -1 for current user ID.
- * pid: Process ID of the app which initially requested this AudioTrack
- * for power management tracking, or -1 for current process ID.
+ * identity: The identity of the app which initiallly requested this AudioTrack.
+ * Includes the UID and PID for power management tracking, or -1 for
+ * current user/process ID, plus the package name.
* pAttributes: If not NULL, supersedes streamType for use case selection.
* doNotReconnect: If set to true, AudioTrack won't automatically recreate the IAudioTrack
binder to AudioFlinger.
@@ -259,13 +259,12 @@
audio_session_t sessionId = AUDIO_SESSION_ALLOCATE,
transfer_type transferType = TRANSFER_DEFAULT,
const audio_offload_info_t *offloadInfo = NULL,
- uid_t uid = AUDIO_UID_INVALID,
- pid_t pid = -1,
+ const media::permission::Identity& identity =
+ media::permission::Identity(),
const audio_attributes_t* pAttributes = NULL,
bool doNotReconnect = false,
float maxRequiredSpeed = 1.0f,
- audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE,
- const std::string& opPackageName = "");
+ audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE);
/* Creates an audio track and registers it with AudioFlinger.
* With this constructor, the track is configured for static buffer mode.
@@ -291,12 +290,11 @@
audio_session_t sessionId = AUDIO_SESSION_ALLOCATE,
transfer_type transferType = TRANSFER_DEFAULT,
const audio_offload_info_t *offloadInfo = NULL,
- uid_t uid = AUDIO_UID_INVALID,
- pid_t pid = -1,
+ const media::permission::Identity& identity =
+ media::permission::Identity(),
const audio_attributes_t* pAttributes = NULL,
bool doNotReconnect = false,
- float maxRequiredSpeed = 1.0f,
- const std::string& opPackageName = "");
+ float maxRequiredSpeed = 1.0f);
/* Terminates the AudioTrack and unregisters it from AudioFlinger.
* Also destroys all resources associated with the AudioTrack.
@@ -340,8 +338,8 @@
audio_session_t sessionId = AUDIO_SESSION_ALLOCATE,
transfer_type transferType = TRANSFER_DEFAULT,
const audio_offload_info_t *offloadInfo = NULL,
- uid_t uid = AUDIO_UID_INVALID,
- pid_t pid = -1,
+ const media::permission::Identity& identity =
+ media::permission::Identity(),
const audio_attributes_t* pAttributes = NULL,
bool doNotReconnect = false,
float maxRequiredSpeed = 1.0f,
@@ -1311,8 +1309,6 @@
sp<media::VolumeHandler> mVolumeHandler;
- const std::string mOpPackageName;
-
private:
class DeathNotifier : public IBinder::DeathRecipient {
public:
@@ -1325,8 +1321,7 @@
sp<DeathNotifier> mDeathNotifier;
uint32_t mSequence; // incremented for each new IAudioTrack attempt
- uid_t mClientUid;
- pid_t mClientPid;
+ media::permission::Identity mClientIdentity;
wp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index 9a8014d..efd7fed 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -37,6 +37,7 @@
#include <android/media/BnAudioFlingerService.h>
#include <android/media/BpAudioFlingerService.h>
+#include <android/media/permission/Identity.h>
#include "android/media/CreateEffectRequest.h"
#include "android/media/CreateEffectResponse.h"
#include "android/media/CreateRecordRequest.h"
@@ -78,7 +79,6 @@
uint32_t notificationsPerBuffer;
float speed;
sp<media::IAudioTrackCallback> audioTrackCallback;
- std::string opPackageName;
/* input/output */
audio_output_flags_t flags;
@@ -127,7 +127,7 @@
audio_attributes_t attr;
audio_config_base_t config;
AudioClient clientInfo;
- String16 opPackageName;
+ media::permission::Identity identity;
audio_unique_id_t riid;
/* input/output */
diff --git a/media/libaudioclient/tests/test_create_audiorecord.cpp b/media/libaudioclient/tests/test_create_audiorecord.cpp
index cf6a734..57676c1 100644
--- a/media/libaudioclient/tests/test_create_audiorecord.cpp
+++ b/media/libaudioclient/tests/test_create_audiorecord.cpp
@@ -19,6 +19,7 @@
#include <string.h>
#include <unistd.h>
+#include <android/media/permission/Identity.h>
#include <binder/MemoryBase.h>
#include <binder/MemoryDealer.h>
#include <binder/MemoryHeapBase.h>
@@ -32,19 +33,24 @@
namespace android {
+using media::permission::Identity;
+
int testRecord(FILE *inputFile, int outputFileFd)
{
char line[MAX_INPUT_FILE_LINE_LENGTH];
uint32_t testCount = 0;
Vector<String16> args;
int ret = 0;
+ // TODO b/182392769: use identity util
+ Identity identity;
+ identity.packageName = PACKAGE_NAME;
if (inputFile == nullptr) {
sp<AudioRecord> record = new AudioRecord(AUDIO_SOURCE_DEFAULT,
0 /* sampleRate */,
AUDIO_FORMAT_DEFAULT,
AUDIO_CHANNEL_IN_MONO,
- String16(PACKAGE_NAME));
+ identity);
if (record == 0 || record->initCheck() != NO_ERROR) {
write(outputFileFd, "Error creating AudioRecord\n",
sizeof("Error creating AudioRecord\n"));
@@ -90,7 +96,7 @@
memset(&attributes, 0, sizeof(attributes));
attributes.source = inputSource;
- sp<AudioRecord> record = new AudioRecord(String16(PACKAGE_NAME));
+ sp<AudioRecord> record = new AudioRecord(identity);
record->set(AUDIO_SOURCE_DEFAULT,
sampleRate,
diff --git a/media/libeffects/lvm/lib/Android.bp b/media/libeffects/lvm/lib/Android.bp
index a044295..5d75055 100644
--- a/media/libeffects/lvm/lib/Android.bp
+++ b/media/libeffects/lvm/lib/Android.bp
@@ -59,7 +59,6 @@
"Eq/src/LVEQNB_Init.cpp",
"Eq/src/LVEQNB_Process.cpp",
"Eq/src/LVEQNB_Tables.cpp",
- "Common/src/InstAlloc.cpp",
"Common/src/DC_2I_D16_TRC_WRA_01.cpp",
"Common/src/DC_2I_D16_TRC_WRA_01_Init.cpp",
"Common/src/Copy_16.cpp",
@@ -146,11 +145,9 @@
"Reverb/src/LVREV_ClearAudioBuffers.cpp",
"Reverb/src/LVREV_GetControlParameters.cpp",
"Reverb/src/LVREV_GetInstanceHandle.cpp",
- "Reverb/src/LVREV_GetMemoryTable.cpp",
"Reverb/src/LVREV_Process.cpp",
"Reverb/src/LVREV_SetControlParameters.cpp",
"Reverb/src/LVREV_Tables.cpp",
- "Common/src/InstAlloc.cpp",
"Common/src/LoadConst_32.cpp",
"Common/src/From2iToMono_32.cpp",
"Common/src/Mult3s_32x16.cpp",
diff --git a/media/libeffects/lvm/lib/Bass/src/LVDBE_Control.cpp b/media/libeffects/lvm/lib/Bass/src/LVDBE_Control.cpp
index 3fc9e95..9fe8116 100644
--- a/media/libeffects/lvm/lib/Bass/src/LVDBE_Control.cpp
+++ b/media/libeffects/lvm/lib/Bass/src/LVDBE_Control.cpp
@@ -277,13 +277,15 @@
/*
* Create biquad instance
*/
- pInstance->pHPFBiquad.reset(
- new android::audio_utils::BiquadFilter<LVM_FLOAT>(pParams->NrChannels));
-
+ if (pInstance->Params.NrChannels != pParams->NrChannels) {
+ pInstance->pHPFBiquad.reset(
+ new android::audio_utils::BiquadFilter<LVM_FLOAT>(pParams->NrChannels));
+ }
/*
* Update the filters
*/
if ((pInstance->Params.SampleRate != pParams->SampleRate) ||
+ (pInstance->Params.NrChannels != pParams->NrChannels) ||
(pInstance->Params.CentreFrequency != pParams->CentreFrequency)) {
LVDBE_SetFilters(pInstance, /* Instance pointer */
pParams); /* New parameters */
diff --git a/media/libeffects/lvm/lib/Bass/src/LVDBE_Init.cpp b/media/libeffects/lvm/lib/Bass/src/LVDBE_Init.cpp
index 761c6ce..b113f48 100644
--- a/media/libeffects/lvm/lib/Bass/src/LVDBE_Init.cpp
+++ b/media/libeffects/lvm/lib/Bass/src/LVDBE_Init.cpp
@@ -57,7 +57,7 @@
* Create the instance handle if not already initialised
*/
if (*phInstance == LVM_NULL) {
- *phInstance = new LVDBE_Instance_t;
+ *phInstance = new LVDBE_Instance_t{};
}
pInstance = (LVDBE_Instance_t*)*phInstance;
@@ -79,6 +79,7 @@
pInstance->Params.SampleRate = LVDBE_FS_8000;
pInstance->Params.VolumeControl = LVDBE_VOLUME_OFF;
pInstance->Params.VolumedB = 0;
+ pInstance->Params.NrChannels = FCC_2;
/*
* Create pointer to data and coef memory
@@ -91,7 +92,7 @@
* Create biquad instance
*/
pInstance->pHPFBiquad.reset(
- new android::audio_utils::BiquadFilter<LVM_FLOAT>(LVM_MAX_CHANNELS));
+ new android::audio_utils::BiquadFilter<LVM_FLOAT>(pInstance->Params.NrChannels));
pInstance->pBPFBiquad.reset(new android::audio_utils::BiquadFilter<LVM_FLOAT>(FCC_1));
/*
diff --git a/media/libeffects/lvm/lib/Bundle/src/LVM_Init.cpp b/media/libeffects/lvm/lib/Bundle/src/LVM_Init.cpp
index b092970..9f5f448 100644
--- a/media/libeffects/lvm/lib/Bundle/src/LVM_Init.cpp
+++ b/media/libeffects/lvm/lib/Bundle/src/LVM_Init.cpp
@@ -25,7 +25,6 @@
#include "LVM_Private.h"
#include "LVM_Tables.h"
#include "VectorArithmetic.h"
-#include "InstAlloc.h"
/****************************************************************************************/
/* */
@@ -93,7 +92,7 @@
/*
* Create the instance handle
*/
- *phInstance = new LVM_Instance_t;
+ *phInstance = new LVM_Instance_t{};
pInstance = (LVM_Instance_t*)*phInstance;
pInstance->InstParams = *pInstParams;
diff --git a/media/libeffects/lvm/lib/Common/lib/InstAlloc.h b/media/libeffects/lvm/lib/Common/lib/InstAlloc.h
deleted file mode 100644
index 17699ef..0000000
--- a/media/libeffects/lvm/lib/Common/lib/InstAlloc.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 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 __INSTALLOC_H__
-#define __INSTALLOC_H__
-
-#include "LVM_Types.h"
-/*######################################################################################*/
-/* Type declarations */
-/*######################################################################################*/
-typedef struct {
- LVM_UINT32 TotalSize; /* Accumulative total memory size */
- uintptr_t pNextMember; /* Pointer to the next instance member to be allocated */
-} INST_ALLOC;
-
-/*######################################################################################*/
-/* Function prototypes */
-/*######################################################################################*/
-
-/****************************************************************************************
- * Name : InstAlloc_Init()
- * Input : pms - Pointer to the INST_ALLOC instance
- StartAddr - Base address of the instance memory
- * Returns : Error code
- * Description : Initializes the instance distribution and memory size calculation function
- * Remarks :
- ****************************************************************************************/
-
-void InstAlloc_Init(INST_ALLOC* pms, void* StartAddr);
-
-/****************************************************************************************
- * Name : InstAlloc_AddMember()
- * Input : pms - Pointer to the INST_ALLOC instance
- Size - The size in bytes of the new added member
- * Returns : A pointer to the new added member
- * Description : Allocates space for a new member in the instance memory and returns
- a pointer to this new member. The start address of all members will
- be 32 bit alligned.
- * Remarks :
- ****************************************************************************************/
-
-void* InstAlloc_AddMember(INST_ALLOC* pms, LVM_UINT32 Size);
-
-/****************************************************************************************
- * Name : InstAlloc_GetTotal()
- * Input : pms - Pointer to the INST_ALLOC instance
- * Returns : The instance memory size
- * Description : This functions returns the calculated instance memory size
- * Remarks :
- ****************************************************************************************/
-
-LVM_UINT32 InstAlloc_GetTotal(INST_ALLOC* pms);
-
-void* InstAlloc_AddMemberAllRet(INST_ALLOC* pms, LVM_UINT32 Size[], void** ptr);
-
-void* InstAlloc_AddMemberAll(INST_ALLOC* pms, LVM_UINT32 Size[], LVM_MemoryTable_st* pMemoryTable);
-
-void InstAlloc_InitAll(INST_ALLOC* pms, LVM_MemoryTable_st* pMemoryTable);
-
-void InstAlloc_InitAll_NULL(INST_ALLOC* pms);
-
-#endif /* __JBS_INSTALLOC_H__ */
diff --git a/media/libeffects/lvm/lib/Common/lib/LVM_Types.h b/media/libeffects/lvm/lib/Common/lib/LVM_Types.h
index 5cdcf35..7cfaf27 100644
--- a/media/libeffects/lvm/lib/Common/lib/LVM_Types.h
+++ b/media/libeffects/lvm/lib/Common/lib/LVM_Types.h
@@ -134,27 +134,6 @@
return LVM_FS_INVALID;
}
-/* Memory Types */
-typedef enum {
- LVM_PERSISTENT_SLOW_DATA = LVM_MEMREGION_PERSISTENT_SLOW_DATA,
- LVM_PERSISTENT_FAST_DATA = LVM_MEMREGION_PERSISTENT_FAST_DATA,
- LVM_PERSISTENT_FAST_COEF = LVM_MEMREGION_PERSISTENT_FAST_COEF,
- LVM_TEMPORARY_FAST = LVM_MEMREGION_TEMPORARY_FAST,
- LVM_MEMORYTYPE_DUMMY = LVM_MAXENUM
-} LVM_MemoryTypes_en;
-
-/* Memory region definition */
-typedef struct {
- LVM_UINT32 Size; /* Region size in bytes */
- LVM_MemoryTypes_en Type; /* Region type */
- void* pBaseAddress; /* Pointer to the region base address */
-} LVM_MemoryRegion_st;
-
-/* Memory table containing the region definitions */
-typedef struct {
- LVM_MemoryRegion_st Region[LVM_NR_MEMORY_REGIONS]; /* One definition for each region */
-} LVM_MemoryTable_st;
-
/****************************************************************************************/
/* */
/* Standard Function Prototypes */
diff --git a/media/libeffects/lvm/lib/Common/src/InstAlloc.cpp b/media/libeffects/lvm/lib/Common/src/InstAlloc.cpp
deleted file mode 100644
index 2cfe056..0000000
--- a/media/libeffects/lvm/lib/Common/src/InstAlloc.cpp
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 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 "InstAlloc.h"
-
-/****************************************************************************************
- * Name : InstAlloc_Init()
- * Input : pms - Pointer to the INST_ALLOC instance
- StartAddr - Base address of the instance memory
- * Returns : Error code
- * Description : Initializes the instance distribution and memory size calculation function
- * Remarks :
- ****************************************************************************************/
-
-void InstAlloc_Init(INST_ALLOC* pms, void* StartAddr) {
- pms->TotalSize = 3;
- pms->pNextMember = (((uintptr_t)StartAddr + 3) & (uintptr_t)~3);
-}
-
-/****************************************************************************************
- * Name : InstAlloc_AddMember()
- * Input : pms - Pointer to the INST_ALLOC instance
- Size - The size in bytes of the new added member
- * Returns : A pointer to the new added member
- * Description : Allocates space for a new member in the instance memory and returns
- a pointer to this new member. The start address of all members will
- be 32 bit alligned.
- * Remarks :
- ****************************************************************************************/
-
-void* InstAlloc_AddMember(INST_ALLOC* pms, LVM_UINT32 Size) {
- void* NewMemberAddress; /* Variable to temporarily store the return value */
- NewMemberAddress = (void*)pms->pNextMember;
-
- Size = ((Size + 3) & (LVM_UINT32)~3); /* Ceil the size to a multiple of four */
-
- pms->TotalSize += Size;
- pms->pNextMember += Size;
-
- return (NewMemberAddress);
-}
-
-/****************************************************************************************
- * Name : InstAlloc_GetTotal()
- * Input : pms - Pointer to the INST_ALLOC instance
- * Returns : The instance memory size
- * Description : This functions returns the calculated instance memory size
- * Remarks :
- ****************************************************************************************/
-
-LVM_UINT32 InstAlloc_GetTotal(INST_ALLOC* pms) {
- if (pms->TotalSize > 3) {
- return (pms->TotalSize);
- } else {
- return 0; /* No memory added */
- }
-}
-
-void InstAlloc_InitAll(INST_ALLOC* pms, LVM_MemoryTable_st* pMemoryTable) {
- uintptr_t StartAddr;
-
- StartAddr = (uintptr_t)pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].pBaseAddress;
-
- pms[0].TotalSize = 3;
- pms[0].pNextMember = ((StartAddr + 3) & (uintptr_t)~3);
-
- StartAddr = (uintptr_t)pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].pBaseAddress;
-
- pms[1].TotalSize = 3;
- pms[1].pNextMember = ((StartAddr + 3) & (uintptr_t)~3);
-
- StartAddr = (uintptr_t)pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].pBaseAddress;
-
- pms[2].TotalSize = 3;
- pms[2].pNextMember = ((StartAddr + 3) & (uintptr_t)~3);
-
- StartAddr = (uintptr_t)pMemoryTable->Region[LVM_TEMPORARY_FAST].pBaseAddress;
-
- pms[3].TotalSize = 3;
- pms[3].pNextMember = ((StartAddr + 3) & (uintptr_t)~3);
-}
-
-/****************************************************************************************
- * Name : InstAlloc_InitAll_NULL()
- * Input : pms - Pointer to array of four INST_ALLOC instances
- * Returns : Nothing
- * Description : This function reserves Size of 3 bytes for all memory regions and
- * intializes pNextMember for all regions to 0
- * Remarks :
- ****************************************************************************************/
-
-void InstAlloc_InitAll_NULL(INST_ALLOC* pms) {
- pms[0].TotalSize = 3;
- pms[0].pNextMember = 0;
-
- pms[1].TotalSize = 3;
- pms[1].pNextMember = 0;
-
- pms[2].TotalSize = 3;
- pms[2].pNextMember = 0;
-
- pms[3].TotalSize = 3;
- pms[3].pNextMember = 0;
-}
-
-void* InstAlloc_AddMemberAll(INST_ALLOC* pms, LVM_UINT32 Size[], LVM_MemoryTable_st* pMemoryTable) {
- void* NewMemberAddress; /* Variable to temporarily store the return value */
-
- /* coverity[returned_pointer] Ignore coverity warning that ptr is not used */
- NewMemberAddress =
- InstAlloc_AddMember(&pms[LVM_PERSISTENT_SLOW_DATA], Size[LVM_PERSISTENT_SLOW_DATA]);
-
- pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].Size =
- InstAlloc_GetTotal(&pms[LVM_PERSISTENT_SLOW_DATA]);
- pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].Type = LVM_PERSISTENT_SLOW_DATA;
- pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].pBaseAddress = LVM_NULL;
-
- NewMemberAddress =
- InstAlloc_AddMember(&pms[LVM_PERSISTENT_FAST_DATA], Size[LVM_PERSISTENT_FAST_DATA]);
-
- pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].Size =
- InstAlloc_GetTotal(&pms[LVM_PERSISTENT_FAST_DATA]);
- pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].Type = LVM_PERSISTENT_FAST_DATA;
- pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].pBaseAddress = LVM_NULL;
-
- NewMemberAddress =
- InstAlloc_AddMember(&pms[LVM_PERSISTENT_FAST_COEF], Size[LVM_PERSISTENT_FAST_COEF]);
-
- pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].Size =
- InstAlloc_GetTotal(&pms[LVM_PERSISTENT_FAST_COEF]);
- pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].Type = LVM_PERSISTENT_FAST_COEF;
- pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].pBaseAddress = LVM_NULL;
-
- NewMemberAddress = InstAlloc_AddMember(&pms[LVM_TEMPORARY_FAST], Size[LVM_TEMPORARY_FAST]);
-
- pMemoryTable->Region[LVM_TEMPORARY_FAST].Size = InstAlloc_GetTotal(&pms[LVM_TEMPORARY_FAST]);
- pMemoryTable->Region[LVM_TEMPORARY_FAST].Type = LVM_TEMPORARY_FAST;
- pMemoryTable->Region[LVM_TEMPORARY_FAST].pBaseAddress = LVM_NULL;
-
- return (NewMemberAddress);
-}
-
-void* InstAlloc_AddMemberAllRet(INST_ALLOC* pms, LVM_UINT32 Size[], void** ptr) {
- ptr[0] = InstAlloc_AddMember(&pms[LVM_PERSISTENT_SLOW_DATA], Size[LVM_PERSISTENT_SLOW_DATA]);
- ptr[1] = InstAlloc_AddMember(&pms[LVM_PERSISTENT_FAST_DATA], Size[LVM_PERSISTENT_FAST_DATA]);
- ptr[2] = InstAlloc_AddMember(&pms[LVM_PERSISTENT_FAST_COEF], Size[LVM_PERSISTENT_FAST_COEF]);
- ptr[3] = InstAlloc_AddMember(&pms[LVM_TEMPORARY_FAST], Size[LVM_TEMPORARY_FAST]);
-
- return (ptr[0]);
-}
diff --git a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Init.cpp b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Init.cpp
index 37e6d4d..3473262 100644
--- a/media/libeffects/lvm/lib/Eq/src/LVEQNB_Init.cpp
+++ b/media/libeffects/lvm/lib/Eq/src/LVEQNB_Init.cpp
@@ -24,7 +24,6 @@
#include <stdlib.h>
#include "LVEQNB.h"
#include "LVEQNB_Private.h"
-#include "InstAlloc.h"
#include <string.h> /* For memset */
/****************************************************************************************/
@@ -52,7 +51,7 @@
LVEQNB_Capabilities_t* pCapabilities, void* pScratch) {
LVEQNB_Instance_t* pInstance;
- *phInstance = new LVEQNB_Instance_t;
+ *phInstance = new LVEQNB_Instance_t{};
pInstance = (LVEQNB_Instance_t*)*phInstance;
pInstance->Capabilities = *pCapabilities;
diff --git a/media/libeffects/lvm/lib/Reverb/lib/LVREV.h b/media/libeffects/lvm/lib/Reverb/lib/LVREV.h
index 489bc6f..82e94da 100644
--- a/media/libeffects/lvm/lib/Reverb/lib/LVREV.h
+++ b/media/libeffects/lvm/lib/Reverb/lib/LVREV.h
@@ -78,11 +78,6 @@
/* */
/****************************************************************************************/
-/* Memory table containing the region definitions */
-typedef struct {
- LVM_MemoryRegion_st Region[LVREV_NR_MEMORY_REGIONS]; /* One definition for each region */
-} LVREV_MemoryTable_st;
-
/* Control Parameter structure */
typedef struct {
/* General parameters */
@@ -121,46 +116,6 @@
/****************************************************************************************/
/* */
-/* FUNCTION: LVREV_GetMemoryTable */
-/* */
-/* DESCRIPTION: */
-/* This function is used to obtain the LVREV module memory requirements to support */
-/* memory allocation. It can also be used to return the memory base address provided */
-/* during memory allocation to support freeing of memory when the LVREV module is no */
-/* longer required. It is called in two ways: */
-/* */
-/* hInstance = NULL Returns the memory requirements */
-/* hInstance = Instance handle Returns the memory requirements and allocated */
-/* base addresses. */
-/* */
-/* When this function is called with hInstance = NULL the memory base address pointers */
-/* will be NULL on return. */
-/* */
-/* When the function is called for freeing memory, hInstance = Instance Handle the */
-/* memory table returns the allocated memory and base addresses used during */
-/* initialisation. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance Handle */
-/* pMemoryTable Pointer to an empty memory table */
-/* pInstanceParams Pointer to the instance parameters */
-/* */
-/* RETURNS: */
-/* LVREV_SUCCESS Succeeded */
-/* LVREV_NULLADDRESS When pMemoryTable is NULL */
-/* LVREV_NULLADDRESS When requesting memory requirements and pInstanceParams */
-/* is NULL */
-/* */
-/* NOTES: */
-/* 1. This function may be interrupted by the LVREV_Process function */
-/* */
-/****************************************************************************************/
-LVREV_ReturnStatus_en LVREV_GetMemoryTable(LVREV_Handle_t hInstance,
- LVREV_MemoryTable_st* pMemoryTable,
- LVREV_InstanceParams_st* pInstanceParams);
-
-/****************************************************************************************/
-/* */
/* FUNCTION: LVREV_GetInstanceHandle */
/* */
/* DESCRIPTION: */
@@ -174,7 +129,6 @@
/* */
/* PARAMETERS: */
/* phInstance Pointer to the instance handle */
-/* pMemoryTable Pointer to the memory definition table */
/* pInstanceParams Pointer to the instance parameters */
/* */
/* RETURNS: */
@@ -186,7 +140,6 @@
/* */
/****************************************************************************************/
LVREV_ReturnStatus_en LVREV_GetInstanceHandle(LVREV_Handle_t* phInstance,
- LVREV_MemoryTable_st* pMemoryTable,
LVREV_InstanceParams_st* pInstanceParams);
/****************************************************************************************/
diff --git a/media/libeffects/lvm/lib/Reverb/src/LVREV_GetInstanceHandle.cpp b/media/libeffects/lvm/lib/Reverb/src/LVREV_GetInstanceHandle.cpp
index bf71634..3a63698 100644
--- a/media/libeffects/lvm/lib/Reverb/src/LVREV_GetInstanceHandle.cpp
+++ b/media/libeffects/lvm/lib/Reverb/src/LVREV_GetInstanceHandle.cpp
@@ -21,7 +21,6 @@
/* */
/****************************************************************************************/
#include "LVREV_Private.h"
-#include "InstAlloc.h"
/****************************************************************************************/
/* */
@@ -34,7 +33,6 @@
/* */
/* PARAMETERS: */
/* phInstance pointer to the instance handle */
-/* pMemoryTable Pointer to the memory definition table */
/* pInstanceParams Pointer to the instance parameters */
/* */
/* RETURNS: */
@@ -46,12 +44,7 @@
/* */
/****************************************************************************************/
LVREV_ReturnStatus_en LVREV_GetInstanceHandle(LVREV_Handle_t* phInstance,
- LVREV_MemoryTable_st* pMemoryTable,
LVREV_InstanceParams_st* pInstanceParams) {
- INST_ALLOC SlowData;
- INST_ALLOC FastData;
- INST_ALLOC FastCoef;
- INST_ALLOC Temporary;
LVREV_Instance_st* pLVREV_Private;
LVM_INT16 i;
LVM_UINT16 MaxBlockSize;
@@ -60,18 +53,9 @@
* Check for error conditions
*/
/* Check for NULL pointers */
- if ((phInstance == LVM_NULL) || (pMemoryTable == LVM_NULL) || (pInstanceParams == LVM_NULL)) {
+ if ((phInstance == LVM_NULL) || (pInstanceParams == LVM_NULL)) {
return LVREV_NULLADDRESS;
}
- /* Check the memory table for NULL pointers */
- for (i = 0; i < LVREV_NR_MEMORY_REGIONS; i++) {
- if (pMemoryTable->Region[i].Size != 0) {
- if (pMemoryTable->Region[i].pBaseAddress == LVM_NULL) {
- return (LVREV_NULLADDRESS);
- }
- }
- }
-
/*
* Check all instance parameters are in range
*/
@@ -88,36 +72,12 @@
}
/*
- * Initialise the InstAlloc instances
- */
- InstAlloc_Init(&SlowData, pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].pBaseAddress);
- InstAlloc_Init(&FastData, pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].pBaseAddress);
- InstAlloc_Init(&FastCoef, pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].pBaseAddress);
- InstAlloc_Init(&Temporary, pMemoryTable->Region[LVM_TEMPORARY_FAST].pBaseAddress);
-
- /*
- * Zero all memory regions
- */
- LoadConst_Float(
- 0, (LVM_FLOAT*)pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].pBaseAddress,
- (LVM_INT16)((pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].Size) / sizeof(LVM_FLOAT)));
- LoadConst_Float(
- 0, (LVM_FLOAT*)pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].pBaseAddress,
- (LVM_INT16)((pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].Size) / sizeof(LVM_FLOAT)));
- LoadConst_Float(
- 0, (LVM_FLOAT*)pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].pBaseAddress,
- (LVM_INT16)((pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].Size) / sizeof(LVM_FLOAT)));
- LoadConst_Float(
- 0, (LVM_FLOAT*)pMemoryTable->Region[LVM_TEMPORARY_FAST].pBaseAddress,
- (LVM_INT16)((pMemoryTable->Region[LVM_TEMPORARY_FAST].Size) / sizeof(LVM_FLOAT)));
- /*
* Set the instance handle if not already initialised
*/
if (*phInstance == LVM_NULL) {
- *phInstance = new LVREV_Instance_st;
+ *phInstance = new LVREV_Instance_st{};
}
pLVREV_Private = (LVREV_Instance_st*)*phInstance;
- pLVREV_Private->MemoryTable = *pMemoryTable;
if (pInstanceParams->NumDelays == LVREV_DELAYLINES_4) {
MaxBlockSize = LVREV_MAX_AP_DELAY[3];
@@ -135,12 +95,9 @@
* Set the data, coefficient and temporary memory pointers
*/
for (size_t i = 0; i < pInstanceParams->NumDelays; i++) {
- pLVREV_Private->pDelay_T[i] = (LVM_FLOAT*)InstAlloc_AddMember(
- &FastData, LVREV_MAX_T_DELAY[i] * sizeof(LVM_FLOAT));
+ pLVREV_Private->pDelay_T[i] = (LVM_FLOAT*)calloc(LVREV_MAX_T_DELAY[i], sizeof(LVM_FLOAT));
/* Scratch for each delay line output */
- pLVREV_Private->pScratchDelayLine[i] =
- (LVM_FLOAT*)InstAlloc_AddMember(&Temporary, sizeof(LVM_FLOAT) * MaxBlockSize);
- LoadConst_Float(0, pLVREV_Private->pDelay_T[i], LVREV_MAX_T_DELAY[i]);
+ pLVREV_Private->pScratchDelayLine[i] = (LVM_FLOAT*)calloc(MaxBlockSize, sizeof(LVM_FLOAT));
}
/* All-pass delay buffer addresses and sizes */
for (size_t i = 0; i < LVREV_DELAYLINES_4; i++) {
@@ -149,12 +106,9 @@
pLVREV_Private->AB_Selection = 1; /* Select smoothing A to B */
/* General purpose scratch */
- pLVREV_Private->pScratch =
- (LVM_FLOAT*)InstAlloc_AddMember(&Temporary, sizeof(LVM_FLOAT) * MaxBlockSize);
+ pLVREV_Private->pScratch = (LVM_FLOAT*)calloc(MaxBlockSize, sizeof(LVM_FLOAT));
/* Mono->stereo input save for end mix */
- pLVREV_Private->pInputSave =
- (LVM_FLOAT*)InstAlloc_AddMember(&Temporary, 2 * sizeof(LVM_FLOAT) * MaxBlockSize);
- LoadConst_Float(0, pLVREV_Private->pInputSave, (LVM_INT16)(MaxBlockSize * 2));
+ pLVREV_Private->pInputSave = (LVM_FLOAT*)calloc(FCC_2 * MaxBlockSize, sizeof(LVM_FLOAT));
/*
* Save the instance parameters in the instance structure
@@ -289,7 +243,28 @@
return LVREV_NULLADDRESS;
}
- delete (LVREV_Instance_st*)hInstance;
+ LVREV_Instance_st* pLVREV_Private = (LVREV_Instance_st*)hInstance;
+
+ for (size_t i = 0; i < pLVREV_Private->InstanceParams.NumDelays; i++) {
+ if (pLVREV_Private->pDelay_T[i]) {
+ free(pLVREV_Private->pDelay_T[i]);
+ pLVREV_Private->pDelay_T[i] = LVM_NULL;
+ }
+ if (pLVREV_Private->pScratchDelayLine[i]) {
+ free(pLVREV_Private->pScratchDelayLine[i]);
+ pLVREV_Private->pScratchDelayLine[i] = LVM_NULL;
+ }
+ }
+ if (pLVREV_Private->pScratch) {
+ free(pLVREV_Private->pScratch);
+ pLVREV_Private->pScratch = LVM_NULL;
+ }
+ if (pLVREV_Private->pInputSave) {
+ free(pLVREV_Private->pInputSave);
+ pLVREV_Private->pInputSave = LVM_NULL;
+ }
+
+ delete pLVREV_Private;
return LVREV_SUCCESS;
}
/* End of file */
diff --git a/media/libeffects/lvm/lib/Reverb/src/LVREV_GetMemoryTable.cpp b/media/libeffects/lvm/lib/Reverb/src/LVREV_GetMemoryTable.cpp
deleted file mode 100644
index 02ceb16..0000000
--- a/media/libeffects/lvm/lib/Reverb/src/LVREV_GetMemoryTable.cpp
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright (C) 2004-2010 NXP Software
- * Copyright (C) 2010 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.
- */
-
-/****************************************************************************************/
-/* */
-/* Includes */
-/* */
-/****************************************************************************************/
-#include "LVREV_Private.h"
-#include "InstAlloc.h"
-
-/****************************************************************************************/
-/* */
-/* FUNCTION: LVREV_GetMemoryTable */
-/* */
-/* DESCRIPTION: */
-/* This function is used for memory allocation and free. It can be called in */
-/* two ways: */
-/* */
-/* hInstance = NULL Returns the memory requirements */
-/* hInstance = Instance handle Returns the memory requirements and allocated */
-/* base addresses. */
-/* */
-/* When this function is called for memory allocation (hInstance=NULL) the memory */
-/* base address pointers are NULL on return. */
-/* */
-/* When the function is called for free (hInstance = Instance Handle) the memory */
-/* table returns the allocated memory and base addresses used during initialisation. */
-/* */
-/* PARAMETERS: */
-/* hInstance Instance Handle */
-/* pMemoryTable Pointer to an empty memory table */
-/* pInstanceParams Pointer to the instance parameters */
-/* */
-/* RETURNS: */
-/* LVREV_Success Succeeded */
-/* LVREV_NULLADDRESS When pMemoryTable is NULL */
-/* LVREV_NULLADDRESS When requesting memory requirements and pInstanceParams */
-/* is NULL */
-/* */
-/* NOTES: */
-/* 1. This function may be interrupted by the LVREV_Process function */
-/* */
-/****************************************************************************************/
-LVREV_ReturnStatus_en LVREV_GetMemoryTable(LVREV_Handle_t hInstance,
- LVREV_MemoryTable_st* pMemoryTable,
- LVREV_InstanceParams_st* pInstanceParams) {
- INST_ALLOC SlowData;
- INST_ALLOC FastData;
- INST_ALLOC FastCoef;
- INST_ALLOC Temporary;
- LVM_UINT16 MaxBlockSize;
-
- /*
- * Check for error conditions
- */
- /* Check for NULL pointer */
- if (pMemoryTable == LVM_NULL) {
- return (LVREV_NULLADDRESS);
- }
-
- /*
- * Check all instance parameters are in range
- */
- if (pInstanceParams != LVM_NULL) {
- /*
- * Call for memory allocation, so check the parameters
- */
- /* Check for a non-zero block size */
- if (pInstanceParams->MaxBlockSize == 0) {
- return LVREV_OUTOFRANGE;
- }
-
- /* Check for a valid number of delay lines */
- if ((pInstanceParams->NumDelays != LVREV_DELAYLINES_1) &&
- (pInstanceParams->NumDelays != LVREV_DELAYLINES_2) &&
- (pInstanceParams->NumDelays != LVREV_DELAYLINES_4)) {
- return LVREV_OUTOFRANGE;
- }
- }
-
- /*
- * Initialise the InstAlloc instances
- */
- InstAlloc_Init(&SlowData, (void*)LVM_NULL);
- InstAlloc_Init(&FastData, (void*)LVM_NULL);
- InstAlloc_Init(&FastCoef, (void*)LVM_NULL);
- InstAlloc_Init(&Temporary, (void*)LVM_NULL);
-
- /*
- * Fill in the memory table
- */
- if (hInstance == LVM_NULL) {
- /*
- * Check for null pointers
- */
- if (pInstanceParams == LVM_NULL) {
- return (LVREV_NULLADDRESS);
- }
-
- /*
- * Select the maximum internal block size
- */
- if (pInstanceParams->NumDelays == LVREV_DELAYLINES_4) {
- MaxBlockSize = LVREV_MAX_AP_DELAY[3];
- } else if (pInstanceParams->NumDelays == LVREV_DELAYLINES_2) {
- MaxBlockSize = LVREV_MAX_AP_DELAY[1];
- } else {
- MaxBlockSize = LVREV_MAX_AP_DELAY[0];
- }
-
- if (MaxBlockSize > pInstanceParams->MaxBlockSize) {
- MaxBlockSize = pInstanceParams->MaxBlockSize;
- }
-
- /*
- * Slow data memory
- */
- InstAlloc_AddMember(&SlowData, sizeof(LVREV_Instance_st));
- pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].Size = InstAlloc_GetTotal(&SlowData);
- pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].Type = LVM_PERSISTENT_SLOW_DATA;
- pMemoryTable->Region[LVM_PERSISTENT_SLOW_DATA].pBaseAddress = LVM_NULL;
-
- /*
- * Persistent fast data memory
- */
- for (size_t i = 0; i < pInstanceParams->NumDelays; i++) {
- InstAlloc_AddMember(&FastData, LVREV_MAX_T_DELAY[i] * sizeof(LVM_FLOAT));
- }
-
- pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].Size = InstAlloc_GetTotal(&FastData);
- pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].Type = LVM_PERSISTENT_FAST_DATA;
- pMemoryTable->Region[LVM_PERSISTENT_FAST_DATA].pBaseAddress = LVM_NULL;
-
- /*
- * Persistent fast coefficient memory
- */
- pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].Size = InstAlloc_GetTotal(&FastCoef);
- pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].Type = LVM_PERSISTENT_FAST_COEF;
- pMemoryTable->Region[LVM_PERSISTENT_FAST_COEF].pBaseAddress = LVM_NULL;
-
- /*
- * Temporary fast memory
- */
- /* General purpose scratch memory */
- InstAlloc_AddMember(&Temporary, sizeof(LVM_FLOAT) * MaxBlockSize);
- /* Mono->stereo input saved for end mix */
- InstAlloc_AddMember(&Temporary, 2 * sizeof(LVM_FLOAT) * MaxBlockSize);
- for (size_t i = 0; i < pInstanceParams->NumDelays; i++) {
- /* A Scratch buffer for each delay line */
- InstAlloc_AddMember(&Temporary, sizeof(LVM_FLOAT) * MaxBlockSize);
- }
-
- pMemoryTable->Region[LVM_TEMPORARY_FAST].Size = InstAlloc_GetTotal(&Temporary);
- pMemoryTable->Region[LVM_TEMPORARY_FAST].Type = LVM_TEMPORARY_FAST;
- pMemoryTable->Region[LVM_TEMPORARY_FAST].pBaseAddress = LVM_NULL;
-
- } else {
- LVREV_Instance_st* pLVREV_Private = (LVREV_Instance_st*)hInstance;
-
- /*
- * Read back memory allocation table
- */
- *pMemoryTable = pLVREV_Private->MemoryTable;
- }
-
- return (LVREV_SUCCESS);
-}
-
-/* End of file */
diff --git a/media/libeffects/lvm/lib/Reverb/src/LVREV_Private.h b/media/libeffects/lvm/lib/Reverb/src/LVREV_Private.h
index 33f8165..9a2f9ca 100644
--- a/media/libeffects/lvm/lib/Reverb/src/LVREV_Private.h
+++ b/media/libeffects/lvm/lib/Reverb/src/LVREV_Private.h
@@ -103,11 +103,9 @@
/* */
/****************************************************************************************/
-
typedef struct {
/* General */
LVREV_InstanceParams_st InstanceParams; /* Initialisation time instance parameters */
- LVREV_MemoryTable_st MemoryTable; /* Memory table */
LVREV_ControlParams_st CurrentParams; /* Parameters being used */
LVREV_ControlParams_st NewParams; /* New parameters from the \
calling application */
diff --git a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Init.cpp b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Init.cpp
index 5ca8543..a0f28b1 100644
--- a/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Init.cpp
+++ b/media/libeffects/lvm/lib/SpectrumAnalyzer/src/LVPSA_Init.cpp
@@ -18,7 +18,6 @@
#include <stdlib.h>
#include "LVPSA.h"
#include "LVPSA_Private.h"
-#include "InstAlloc.h"
/************************************************************************************/
/* */
@@ -49,7 +48,7 @@
LVM_UINT32 BufferLength = 0;
/* Set the instance handle if not already initialised */
- *phInstance = new LVPSA_InstancePr_t;
+ *phInstance = new LVPSA_InstancePr_t{};
pLVPSA_Inst = (LVPSA_InstancePr_t*)*phInstance;
pLVPSA_Inst->pScratch = pScratch;
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Equaliser.cpp b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Equaliser.cpp
index 1746786..2b628f1 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Equaliser.cpp
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Equaliser.cpp
@@ -72,8 +72,8 @@
std::array<LVM_FLOAT, android::audio_utils::kBiquadNumCoefs> coefs = {
pEqualiserCoefTable[Offset].A0, pEqualiserCoefTable[Offset].A1,
- pEqualiserCoefTable[Offset].A2, -(pEqualiserCoefTable[Offset].B1),
- -(pEqualiserCoefTable[Offset].B2)};
+ pEqualiserCoefTable[Offset].A2, pEqualiserCoefTable[Offset].B1,
+ pEqualiserCoefTable[Offset].B2};
pInstance->pEqBiquad.reset(new android::audio_utils::BiquadFilter<LVM_FLOAT>(
(pParams->NrChannels == FCC_1) ? FCC_1 : FCC_2, coefs));
}
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Init.cpp b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Init.cpp
index d60b360..dd1baf3 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Init.cpp
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Init.cpp
@@ -55,7 +55,7 @@
* Create the instance handle if not already initialised
*/
if (*phInstance == LVM_NULL) {
- *phInstance = new LVCS_Instance_t;
+ *phInstance = new LVCS_Instance_t{};
}
pInstance = (LVCS_Instance_t*)*phInstance;
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_ReverbGenerator.cpp b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_ReverbGenerator.cpp
index 12b1dc3..c5b6598 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_ReverbGenerator.cpp
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_ReverbGenerator.cpp
@@ -93,8 +93,8 @@
std::array<LVM_FLOAT, android::audio_utils::kBiquadNumCoefs> coefs = {
pReverbCoefTable[Offset].A0, pReverbCoefTable[Offset].A1,
- pReverbCoefTable[Offset].A2, -(pReverbCoefTable[Offset].B1),
- -(pReverbCoefTable[Offset].B2)};
+ pReverbCoefTable[Offset].A2, pReverbCoefTable[Offset].B1,
+ pReverbCoefTable[Offset].B2};
pInstance->pRevBiquad.reset(new android::audio_utils::BiquadFilter<LVM_FLOAT>(
(pParams->NrChannels == FCC_1) ? FCC_1 : FCC_2, coefs));
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_StereoEnhancer.cpp b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_StereoEnhancer.cpp
index e3ff604..3ca25f9 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_StereoEnhancer.cpp
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_StereoEnhancer.cpp
@@ -68,7 +68,7 @@
std::array<LVM_FLOAT, android::audio_utils::kBiquadNumCoefs> coefs = {
LVCS_SEMidCoefTable[Offset].A0, LVCS_SEMidCoefTable[Offset].A1, 0.0,
- -(LVCS_SEMidCoefTable[Offset].B1), 0.0};
+ LVCS_SEMidCoefTable[Offset].B1, 0.0};
pInstance->pSEMidBiquad.reset(
new android::audio_utils::BiquadFilter<LVM_FLOAT>(FCC_1, coefs));
@@ -77,7 +77,7 @@
/* Side filter */
coefs = {pSESideCoefs[Offset].A0, pSESideCoefs[Offset].A1, pSESideCoefs[Offset].A2,
- -(pSESideCoefs[Offset].B1), -(pSESideCoefs[Offset].B2)};
+ pSESideCoefs[Offset].B1, pSESideCoefs[Offset].B2};
pInstance->pSESideBiquad.reset(
new android::audio_utils::BiquadFilter<LVM_FLOAT>(FCC_1, coefs));
}
diff --git a/media/libeffects/lvm/tests/Android.bp b/media/libeffects/lvm/tests/Android.bp
index 639af4d..9939ed1 100644
--- a/media/libeffects/lvm/tests/Android.bp
+++ b/media/libeffects/lvm/tests/Android.bp
@@ -10,12 +10,42 @@
}
cc_test {
+ name: "EffectReverbTest",
+ vendor: true,
+ gtest: true,
+ host_supported: true,
+ srcs: [
+ "EffectReverbTest.cpp",
+ "EffectTestHelper.cpp",
+ ],
+ include_dirs: [
+ "frameworks/av/media/libeffects/lvm/lib/Common/lib",
+ "frameworks/av/media/libeffects/lvm/wrapper/Reverb",
+ ],
+ static_libs: [
+ "libaudioutils",
+ "libreverb",
+ "libreverbwrapper",
+ ],
+ shared_libs: [
+ "liblog",
+ ],
+ header_libs: [
+ "libaudioeffects",
+ "libhardware_headers",
+ ],
+}
+
+cc_test {
name: "EffectBundleTest",
vendor: true,
gtest: true,
host_supported: true,
test_suites: ["device-tests"],
- srcs: ["EffectBundleTest.cpp"],
+ srcs: [
+ "EffectBundleTest.cpp",
+ "EffectTestHelper.cpp",
+ ],
static_libs: [
"libaudioutils",
"libbundlewrapper",
diff --git a/media/libeffects/lvm/tests/EffectBundleTest.cpp b/media/libeffects/lvm/tests/EffectBundleTest.cpp
index aae09de..881ffb1 100644
--- a/media/libeffects/lvm/tests/EffectBundleTest.cpp
+++ b/media/libeffects/lvm/tests/EffectBundleTest.cpp
@@ -14,22 +14,8 @@
* limitations under the License.
*/
-#include <array>
-#include <audio_utils/channels.h>
-#include <audio_utils/primitives.h>
-#include <climits>
-#include <cstdlib>
-#include <gtest/gtest.h>
-#include <hardware/audio_effect.h>
-#include <log/log.h>
-#include <random>
-#include <system/audio.h>
-#include <vector>
-
-extern audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM;
-
-// Corresponds to SNR for 1 bit difference between two int16_t signals
-constexpr float kSNRThreshold = 90.308998;
+#include "EffectTestHelper.h"
+using namespace android;
// Update isBassBoost, if the order of effects is updated
constexpr effect_uuid_t kEffectUuids[] = {
@@ -50,120 +36,15 @@
constexpr size_t kNumEffectUuids = std::size(kEffectUuids);
-constexpr audio_channel_mask_t kChMasks[] = {
- AUDIO_CHANNEL_OUT_MONO, AUDIO_CHANNEL_OUT_STEREO,
- AUDIO_CHANNEL_OUT_2POINT1, AUDIO_CHANNEL_OUT_2POINT0POINT2,
- AUDIO_CHANNEL_OUT_QUAD, AUDIO_CHANNEL_OUT_QUAD_BACK,
- AUDIO_CHANNEL_OUT_QUAD_SIDE, AUDIO_CHANNEL_OUT_SURROUND,
- AUDIO_CHANNEL_INDEX_MASK_4, AUDIO_CHANNEL_OUT_2POINT1POINT2,
- AUDIO_CHANNEL_OUT_3POINT0POINT2, AUDIO_CHANNEL_OUT_PENTA,
- AUDIO_CHANNEL_INDEX_MASK_5, AUDIO_CHANNEL_OUT_3POINT1POINT2,
- AUDIO_CHANNEL_OUT_5POINT1, AUDIO_CHANNEL_OUT_5POINT1_BACK,
- AUDIO_CHANNEL_OUT_5POINT1_SIDE, AUDIO_CHANNEL_INDEX_MASK_6,
- AUDIO_CHANNEL_OUT_6POINT1, AUDIO_CHANNEL_INDEX_MASK_7,
- AUDIO_CHANNEL_OUT_5POINT1POINT2, AUDIO_CHANNEL_OUT_7POINT1,
- AUDIO_CHANNEL_INDEX_MASK_8, AUDIO_CHANNEL_INDEX_MASK_9,
- AUDIO_CHANNEL_INDEX_MASK_10, AUDIO_CHANNEL_INDEX_MASK_11,
- AUDIO_CHANNEL_INDEX_MASK_12, AUDIO_CHANNEL_INDEX_MASK_13,
- AUDIO_CHANNEL_INDEX_MASK_14, AUDIO_CHANNEL_INDEX_MASK_15,
- AUDIO_CHANNEL_INDEX_MASK_16, AUDIO_CHANNEL_INDEX_MASK_17,
- AUDIO_CHANNEL_INDEX_MASK_18, AUDIO_CHANNEL_INDEX_MASK_19,
- AUDIO_CHANNEL_INDEX_MASK_20, AUDIO_CHANNEL_INDEX_MASK_21,
- AUDIO_CHANNEL_INDEX_MASK_22, AUDIO_CHANNEL_INDEX_MASK_23,
- AUDIO_CHANNEL_INDEX_MASK_24,
-};
-
-constexpr size_t kNumChMasks = std::size(kChMasks);
-
-constexpr size_t kSampleRates[] = {8000, 11025, 12000, 16000, 22050, 24000, 32000,
- 44100, 48000, 88200, 96000, 176400, 192000};
-
-constexpr size_t kNumSampleRates = std::size(kSampleRates);
-
-constexpr size_t kFrameCounts[] = {4, 2048};
-
-constexpr size_t kNumFrameCounts = std::size(kFrameCounts);
-
-constexpr size_t kLoopCounts[] = {1, 4};
-
-constexpr size_t kNumLoopCounts = std::size(kLoopCounts);
-
-class EffectBundleHelper {
- public:
- EffectBundleHelper(const effect_uuid_t* uuid, size_t chMask, size_t sampleRate,
- size_t frameCount, size_t loopCount)
- : mUuid(uuid),
- mChMask(chMask),
- mChannelCount(audio_channel_count_from_out_mask(mChMask)),
- mSampleRate(sampleRate),
- mFrameCount(frameCount),
- mLoopCount(loopCount) {}
- void createEffect();
- void releaseEffect();
- void configEffect();
- void process(float* input, float* output);
-
- private:
- const effect_uuid_t* mUuid;
- const size_t mChMask;
- const size_t mChannelCount;
- const size_t mSampleRate;
- const size_t mFrameCount;
- const size_t mLoopCount;
- effect_handle_t mEffectHandle{};
-};
-
-void EffectBundleHelper::createEffect() {
- int status = AUDIO_EFFECT_LIBRARY_INFO_SYM.create_effect(mUuid, 1, 1, &mEffectHandle);
- ASSERT_EQ(status, 0) << "create_effect returned an error " << status << "\n";
-}
-
-void EffectBundleHelper::releaseEffect() {
- int status = AUDIO_EFFECT_LIBRARY_INFO_SYM.release_effect(mEffectHandle);
- ASSERT_EQ(status, 0) << "release_effect returned an error " << status << "\n";
-}
-
-void EffectBundleHelper::configEffect() {
- effect_config_t config{};
- config.inputCfg.samplingRate = config.outputCfg.samplingRate = mSampleRate;
- config.inputCfg.channels = config.outputCfg.channels = mChMask;
- config.inputCfg.format = config.outputCfg.format = AUDIO_FORMAT_PCM_FLOAT;
-
- int reply = 0;
- uint32_t replySize = sizeof(reply);
- int status = (*mEffectHandle)
- ->command(mEffectHandle, EFFECT_CMD_SET_CONFIG, sizeof(effect_config_t),
- &config, &replySize, &reply);
- ASSERT_EQ(status, 0) << "command returned an error " << status << "\n";
- ASSERT_EQ(reply, 0) << "command reply non zero " << reply << "\n";
-
- status = (*mEffectHandle)
- ->command(mEffectHandle, EFFECT_CMD_ENABLE, 0, nullptr, &replySize, &reply);
- ASSERT_EQ(status, 0) << "command enable returned an error " << status << "\n";
- ASSERT_EQ(reply, 0) << "command reply non zero " << reply << "\n";
-}
-
-void EffectBundleHelper::process(float* input, float* output) {
- audio_buffer_t inBuffer = {.frameCount = mFrameCount, .f32 = input};
- audio_buffer_t outBuffer = {.frameCount = mFrameCount, .f32 = output};
- for (size_t i = 0; i < mLoopCount; i++) {
- int status = (*mEffectHandle)->process(mEffectHandle, &inBuffer, &outBuffer);
- ASSERT_EQ(status, 0) << "process returned an error " << status << "\n";
-
- inBuffer.f32 += mFrameCount * mChannelCount;
- outBuffer.f32 += mFrameCount * mChannelCount;
- }
-}
-
typedef std::tuple<int, int, int, int, int> SingleEffectTestParam;
class SingleEffectTest : public ::testing::TestWithParam<SingleEffectTestParam> {
public:
SingleEffectTest()
- : mChMask(kChMasks[std::get<0>(GetParam())]),
+ : mChMask(EffectTestHelper::kChMasks[std::get<0>(GetParam())]),
mChannelCount(audio_channel_count_from_out_mask(mChMask)),
- mSampleRate(kSampleRates[std::get<1>(GetParam())]),
- mFrameCount(kFrameCounts[std::get<2>(GetParam())]),
- mLoopCount(kLoopCounts[std::get<3>(GetParam())]),
+ mSampleRate(EffectTestHelper::kSampleRates[std::get<1>(GetParam())]),
+ mFrameCount(EffectTestHelper::kFrameCounts[std::get<2>(GetParam())]),
+ mLoopCount(EffectTestHelper::kLoopCounts[std::get<3>(GetParam())]),
mTotalFrameCount(mFrameCount * mLoopCount),
mUuid(&kEffectUuids[std::get<4>(GetParam())]) {}
@@ -182,10 +63,10 @@
<< "chMask: " << mChMask << " sampleRate: " << mSampleRate
<< " frameCount: " << mFrameCount << " loopCount: " << mLoopCount);
- EffectBundleHelper effect(mUuid, mChMask, mSampleRate, mFrameCount, mLoopCount);
+ EffectTestHelper effect(mUuid, mChMask, mChMask, mSampleRate, mFrameCount, mLoopCount);
ASSERT_NO_FATAL_FAILURE(effect.createEffect());
- ASSERT_NO_FATAL_FAILURE(effect.configEffect());
+ ASSERT_NO_FATAL_FAILURE(effect.setConfig());
// Initialize input buffer with deterministic pseudo-random values
std::vector<float> input(mTotalFrameCount * mChannelCount);
@@ -199,21 +80,22 @@
ASSERT_NO_FATAL_FAILURE(effect.releaseEffect());
}
-INSTANTIATE_TEST_SUITE_P(EffectBundleTestAll, SingleEffectTest,
- ::testing::Combine(::testing::Range(0, (int)kNumChMasks),
- ::testing::Range(0, (int)kNumSampleRates),
- ::testing::Range(0, (int)kNumFrameCounts),
- ::testing::Range(0, (int)kNumLoopCounts),
- ::testing::Range(0, (int)kNumEffectUuids)));
+INSTANTIATE_TEST_SUITE_P(
+ EffectBundleTestAll, SingleEffectTest,
+ ::testing::Combine(::testing::Range(0, (int)EffectTestHelper::kNumChMasks),
+ ::testing::Range(0, (int)EffectTestHelper::kNumSampleRates),
+ ::testing::Range(0, (int)EffectTestHelper::kNumFrameCounts),
+ ::testing::Range(0, (int)EffectTestHelper::kNumLoopCounts),
+ ::testing::Range(0, (int)kNumEffectUuids)));
typedef std::tuple<int, int, int, int> SingleEffectComparisonTestParam;
class SingleEffectComparisonTest
: public ::testing::TestWithParam<SingleEffectComparisonTestParam> {
public:
SingleEffectComparisonTest()
- : mSampleRate(kSampleRates[std::get<0>(GetParam())]),
- mFrameCount(kFrameCounts[std::get<1>(GetParam())]),
- mLoopCount(kLoopCounts[std::get<2>(GetParam())]),
+ : mSampleRate(EffectTestHelper::kSampleRates[std::get<0>(GetParam())]),
+ mFrameCount(EffectTestHelper::kFrameCounts[std::get<1>(GetParam())]),
+ mLoopCount(EffectTestHelper::kLoopCounts[std::get<2>(GetParam())]),
mTotalFrameCount(mFrameCount * mLoopCount),
mUuid(&kEffectUuids[std::get<3>(GetParam())]) {}
@@ -224,26 +106,6 @@
const effect_uuid_t* mUuid;
};
-template <typename T>
-float computeSnr(const T* ref, const T* tst, size_t count) {
- double signal{};
- double noise{};
-
- for (size_t i = 0; i < count; ++i) {
- const double value(ref[i]);
- const double diff(tst[i] - value);
- signal += value * value;
- noise += diff * diff;
- }
- // Initialized to a value greater than kSNRThreshold to handle
- // cases where ref and tst match exactly
- float snr = kSNRThreshold + 1.0f;
- if (signal > 0.0f && noise > 0.0f) {
- snr = 10.f * log(signal / noise);
- }
- return snr;
-}
-
// Compares first two channels in multi-channel output to stereo output when same effect is applied
TEST_P(SingleEffectComparisonTest, SimpleProcess) {
SCOPED_TRACE(testing::Message() << " sampleRate: " << mSampleRate << " frameCount: "
@@ -264,11 +126,11 @@
mTotalFrameCount * sizeof(float) * FCC_1);
// Apply effect on stereo channels
- EffectBundleHelper stereoEffect(mUuid, AUDIO_CHANNEL_OUT_STEREO, mSampleRate, mFrameCount,
- mLoopCount);
+ EffectTestHelper stereoEffect(mUuid, AUDIO_CHANNEL_OUT_STEREO, AUDIO_CHANNEL_OUT_STEREO,
+ mSampleRate, mFrameCount, mLoopCount);
ASSERT_NO_FATAL_FAILURE(stereoEffect.createEffect());
- ASSERT_NO_FATAL_FAILURE(stereoEffect.configEffect());
+ ASSERT_NO_FATAL_FAILURE(stereoEffect.setConfig());
std::vector<float> stereoOutput(mTotalFrameCount * FCC_2);
ASSERT_NO_FATAL_FAILURE(stereoEffect.process(stereoInput.data(), stereoOutput.data()));
@@ -278,12 +140,12 @@
std::vector<int16_t> stereoRefI16(mTotalFrameCount * FCC_2);
memcpy_to_i16_from_float(stereoRefI16.data(), stereoOutput.data(), mTotalFrameCount * FCC_2);
- for (size_t chMask : kChMasks) {
+ for (size_t chMask : EffectTestHelper::kChMasks) {
size_t channelCount = audio_channel_count_from_out_mask(chMask);
- EffectBundleHelper testEffect(mUuid, chMask, mSampleRate, mFrameCount, mLoopCount);
+ EffectTestHelper testEffect(mUuid, chMask, chMask, mSampleRate, mFrameCount, mLoopCount);
ASSERT_NO_FATAL_FAILURE(testEffect.createEffect());
- ASSERT_NO_FATAL_FAILURE(testEffect.configEffect());
+ ASSERT_NO_FATAL_FAILURE(testEffect.setConfig());
std::vector<float> testInput(mTotalFrameCount * channelCount);
@@ -312,7 +174,8 @@
// SNR must be above the threshold
float snr = computeSnr<int16_t>(stereoRefI16.data(), stereoTestI16.data(),
mTotalFrameCount * FCC_2);
- ASSERT_GT(snr, kSNRThreshold) << "SNR " << snr << "is lower than " << kSNRThreshold;
+ ASSERT_GT(snr, EffectTestHelper::kSNRThreshold)
+ << "SNR " << snr << "is lower than " << EffectTestHelper::kSNRThreshold;
} else {
ASSERT_EQ(0,
memcmp(stereoRefI16.data(), stereoTestI16.data(), mTotalFrameCount * FCC_2))
@@ -321,11 +184,12 @@
}
}
-INSTANTIATE_TEST_SUITE_P(EffectBundleTestAll, SingleEffectComparisonTest,
- ::testing::Combine(::testing::Range(0, (int)kNumSampleRates),
- ::testing::Range(0, (int)kNumFrameCounts),
- ::testing::Range(0, (int)kNumLoopCounts),
- ::testing::Range(0, (int)kNumEffectUuids)));
+INSTANTIATE_TEST_SUITE_P(
+ EffectBundleTestAll, SingleEffectComparisonTest,
+ ::testing::Combine(::testing::Range(0, (int)EffectTestHelper::kNumSampleRates),
+ ::testing::Range(0, (int)EffectTestHelper::kNumFrameCounts),
+ ::testing::Range(0, (int)EffectTestHelper::kNumLoopCounts),
+ ::testing::Range(0, (int)kNumEffectUuids)));
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
diff --git a/media/libeffects/lvm/tests/EffectReverbTest.cpp b/media/libeffects/lvm/tests/EffectReverbTest.cpp
new file mode 100644
index 0000000..59453eb
--- /dev/null
+++ b/media/libeffects/lvm/tests/EffectReverbTest.cpp
@@ -0,0 +1,239 @@
+/*
+ * Copyright 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.
+ */
+
+#include <audio_effects/effect_presetreverb.h>
+#include <VectorArithmetic.h>
+
+#include "EffectTestHelper.h"
+using namespace android;
+
+constexpr effect_uuid_t kEffectUuids[] = {
+ // NXP SW insert environmental reverb
+ {0xc7a511a0, 0xa3bb, 0x11df, 0x860e, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+ // NXP SW insert preset reverb
+ {0x172cdf00, 0xa3bc, 0x11df, 0xa72f, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+ // NXP SW auxiliary environmental reverb
+ {0x4a387fc0, 0x8ab3, 0x11df, 0x8bad, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+ // NXP SW auxiliary preset reverb
+ {0xf29a1400, 0xa3bb, 0x11df, 0x8ddc, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+};
+
+constexpr size_t kNumEffectUuids = std::size(kEffectUuids);
+
+static bool isAuxMode(const effect_uuid_t* uuid) {
+ // Update this, if the order of effects in kEffectUuids is updated
+ return (uuid == &kEffectUuids[2] || uuid == &kEffectUuids[3]);
+}
+
+constexpr int kPresets[] = {
+ REVERB_PRESET_NONE, REVERB_PRESET_SMALLROOM, REVERB_PRESET_MEDIUMROOM,
+ REVERB_PRESET_LARGEROOM, REVERB_PRESET_MEDIUMHALL, REVERB_PRESET_LARGEHALL,
+ REVERB_PRESET_PLATE,
+};
+
+constexpr size_t kNumPresets = std::size(kPresets);
+
+typedef std::tuple<int, int, int, int, int, int> SingleEffectTestParam;
+class SingleEffectTest : public ::testing::TestWithParam<SingleEffectTestParam> {
+ public:
+ SingleEffectTest()
+ : mSampleRate(EffectTestHelper::kSampleRates[std::get<1>(GetParam())]),
+ mFrameCount(EffectTestHelper::kFrameCounts[std::get<2>(GetParam())]),
+ mLoopCount(EffectTestHelper::kLoopCounts[std::get<3>(GetParam())]),
+ mTotalFrameCount(mFrameCount * mLoopCount),
+ mUuid(&kEffectUuids[std::get<4>(GetParam())]),
+ mInChMask(isAuxMode(mUuid) ? AUDIO_CHANNEL_OUT_MONO
+ : EffectTestHelper::kChMasks[std::get<0>(GetParam())]),
+ mInChannelCount(audio_channel_count_from_out_mask(mInChMask)),
+ mOutChMask(EffectTestHelper::kChMasks[std::get<0>(GetParam())]),
+ mOutChannelCount(audio_channel_count_from_out_mask(mOutChMask)),
+ mPreset(kPresets[std::get<5>(GetParam())]) {}
+
+ const size_t mSampleRate;
+ const size_t mFrameCount;
+ const size_t mLoopCount;
+ const size_t mTotalFrameCount;
+ const effect_uuid_t* mUuid;
+ const size_t mInChMask;
+ const size_t mInChannelCount;
+ const size_t mOutChMask;
+ const size_t mOutChannelCount;
+ const size_t mPreset;
+};
+
+// Tests applying a single effect
+TEST_P(SingleEffectTest, SimpleProcess) {
+ SCOPED_TRACE(testing::Message() << "outChMask: " << mOutChMask << " sampleRate: " << mSampleRate
+ << " frameCount: " << mFrameCount
+ << " loopCount: " << mLoopCount << " preset: " << mPreset);
+
+ EffectTestHelper effect(mUuid, mInChMask, mOutChMask, mSampleRate, mFrameCount, mLoopCount);
+
+ ASSERT_NO_FATAL_FAILURE(effect.createEffect());
+ ASSERT_NO_FATAL_FAILURE(effect.setConfig());
+ ASSERT_NO_FATAL_FAILURE(effect.setParam(REVERB_PARAM_PRESET, mPreset));
+
+ // Initialize input buffer with deterministic pseudo-random values
+ std::vector<float> input(mTotalFrameCount * mInChannelCount);
+ std::vector<float> output(mTotalFrameCount * mOutChannelCount);
+ std::minstd_rand gen(mOutChMask);
+ std::uniform_real_distribution<> dis(-1.0f, 1.0f);
+ for (auto& in : input) {
+ in = dis(gen);
+ }
+ ASSERT_NO_FATAL_FAILURE(effect.process(input.data(), output.data()));
+ ASSERT_NO_FATAL_FAILURE(effect.releaseEffect());
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ EffectReverbTestAll, SingleEffectTest,
+ ::testing::Combine(::testing::Range(0, (int)EffectTestHelper::kNumChMasks),
+ ::testing::Range(0, (int)EffectTestHelper::kNumSampleRates),
+ ::testing::Range(0, (int)EffectTestHelper::kNumFrameCounts),
+ ::testing::Range(0, (int)EffectTestHelper::kNumLoopCounts),
+ ::testing::Range(0, (int)kNumEffectUuids),
+ ::testing::Range(0, (int)kNumPresets)));
+
+typedef std::tuple<int, int, int, int, int> SingleEffectComparisonTestParam;
+class SingleEffectComparisonTest
+ : public ::testing::TestWithParam<SingleEffectComparisonTestParam> {
+ public:
+ SingleEffectComparisonTest()
+ : mSampleRate(EffectTestHelper::kSampleRates[std::get<0>(GetParam())]),
+ mFrameCount(EffectTestHelper::kFrameCounts[std::get<1>(GetParam())]),
+ mLoopCount(EffectTestHelper::kLoopCounts[std::get<2>(GetParam())]),
+ mTotalFrameCount(mFrameCount * mLoopCount),
+ mUuid(&kEffectUuids[std::get<3>(GetParam())]),
+ mPreset(kPresets[std::get<4>(GetParam())]) {}
+
+ const size_t mSampleRate;
+ const size_t mFrameCount;
+ const size_t mLoopCount;
+ const size_t mTotalFrameCount;
+ const effect_uuid_t* mUuid;
+ const size_t mPreset;
+};
+
+// Compares first two channels in multi-channel output to stereo output when same effect is applied
+TEST_P(SingleEffectComparisonTest, SimpleProcess) {
+ SCOPED_TRACE(testing::Message()
+ << " sampleRate: " << mSampleRate << " frameCount: " << mFrameCount
+ << " loopCount: " << mLoopCount << " preset: " << mPreset);
+
+ // Initialize mono input buffer with deterministic pseudo-random values
+ std::vector<float> monoInput(mTotalFrameCount);
+
+ std::minstd_rand gen(mSampleRate);
+ std::uniform_real_distribution<> dis(-1.0f, 1.0f);
+ for (auto& in : monoInput) {
+ in = dis(gen);
+ }
+
+ // Generate stereo by repeating mono channel data
+ std::vector<float> stereoInput(mTotalFrameCount * FCC_2);
+ adjust_channels(monoInput.data(), FCC_1, stereoInput.data(), FCC_2, sizeof(float),
+ mTotalFrameCount * sizeof(float) * FCC_1);
+
+ // Apply effect on stereo channels
+ EffectTestHelper stereoEffect(
+ mUuid, isAuxMode(mUuid) ? AUDIO_CHANNEL_OUT_MONO : AUDIO_CHANNEL_OUT_STEREO,
+ AUDIO_CHANNEL_OUT_STEREO, mSampleRate, mFrameCount, mLoopCount);
+
+ ASSERT_NO_FATAL_FAILURE(stereoEffect.createEffect());
+ ASSERT_NO_FATAL_FAILURE(stereoEffect.setConfig());
+ ASSERT_NO_FATAL_FAILURE(stereoEffect.setParam(REVERB_PARAM_PRESET, mPreset));
+
+ std::vector<float> stereoOutput(mTotalFrameCount * FCC_2);
+ ASSERT_NO_FATAL_FAILURE(stereoEffect.process(
+ (isAuxMode(mUuid) ? monoInput.data() : stereoInput.data()), stereoOutput.data()));
+ ASSERT_NO_FATAL_FAILURE(stereoEffect.releaseEffect());
+
+ // Average of both channels data is stored for mono comparison
+ std::vector<float> monoOutput(mTotalFrameCount);
+ From2iToMono_Float((const float*)stereoOutput.data(), monoOutput.data(), mTotalFrameCount);
+
+ // Convert stereo float data to stereo int16_t to be used as reference
+ std::vector<int16_t> stereoRefI16(mTotalFrameCount * FCC_2);
+ memcpy_to_i16_from_float(stereoRefI16.data(), stereoOutput.data(), mTotalFrameCount * FCC_2);
+
+ // mono int16_t to be used as refernece for mono comparison
+ std::vector<int16_t> monoRefI16(mTotalFrameCount);
+ memcpy_to_i16_from_float(monoRefI16.data(), monoOutput.data(), mTotalFrameCount);
+
+ for (size_t outChMask : EffectTestHelper::kChMasks) {
+ size_t outChannelCount = audio_channel_count_from_out_mask(outChMask);
+ size_t inChMask = isAuxMode(mUuid) ? AUDIO_CHANNEL_OUT_MONO : outChMask;
+
+ EffectTestHelper testEffect(mUuid, inChMask, outChMask, mSampleRate, mFrameCount,
+ mLoopCount);
+
+ ASSERT_NO_FATAL_FAILURE(testEffect.createEffect());
+ ASSERT_NO_FATAL_FAILURE(testEffect.setConfig());
+ ASSERT_NO_FATAL_FAILURE(testEffect.setParam(REVERB_PARAM_PRESET, mPreset));
+
+ std::vector<float> testInput(mTotalFrameCount * outChannelCount);
+
+ // Repeat mono channel data to all the channels
+ // adjust_channels() zero fills channels > 2, hence can't be used here
+ for (size_t i = 0; i < mTotalFrameCount; ++i) {
+ auto* fp = &testInput[i * outChannelCount];
+ std::fill(fp, fp + outChannelCount, monoInput[i]);
+ }
+
+ std::vector<float> testOutput(mTotalFrameCount * outChannelCount);
+ ASSERT_NO_FATAL_FAILURE(testEffect.process(
+ (isAuxMode(mUuid) ? monoInput.data() : testInput.data()), testOutput.data()));
+ ASSERT_NO_FATAL_FAILURE(testEffect.releaseEffect());
+
+ if (outChannelCount == FCC_1) {
+ // Convert the test data to int16_t
+ std::vector<int16_t> monoTestI16(mTotalFrameCount);
+ memcpy_to_i16_from_float(monoTestI16.data(), testOutput.data(), mTotalFrameCount);
+
+ ASSERT_EQ(0, memcmp(monoRefI16.data(), monoTestI16.data(), mTotalFrameCount * FCC_2))
+ << "Mono channel do not match with reference output \n";
+ } else {
+ // Extract first two channels
+ std::vector<float> stereoTestOutput(mTotalFrameCount * FCC_2);
+ adjust_channels(testOutput.data(), outChannelCount, stereoTestOutput.data(), FCC_2,
+ sizeof(float), mTotalFrameCount * sizeof(float) * outChannelCount);
+
+ // Convert the test data to int16_t
+ std::vector<int16_t> stereoTestI16(mTotalFrameCount * FCC_2);
+ memcpy_to_i16_from_float(stereoTestI16.data(), stereoTestOutput.data(),
+ mTotalFrameCount * FCC_2);
+
+ ASSERT_EQ(0,
+ memcmp(stereoRefI16.data(), stereoTestI16.data(), mTotalFrameCount * FCC_2))
+ << "First two channels do not match with stereo output \n";
+ }
+ }
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ EffectReverbTestAll, SingleEffectComparisonTest,
+ ::testing::Combine(::testing::Range(0, (int)EffectTestHelper::kNumSampleRates),
+ ::testing::Range(0, (int)EffectTestHelper::kNumFrameCounts),
+ ::testing::Range(0, (int)EffectTestHelper::kNumLoopCounts),
+ ::testing::Range(0, (int)kNumEffectUuids),
+ ::testing::Range(0, (int)kNumPresets)));
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ ALOGV("Test result = %d\n", status);
+ return status;
+}
diff --git a/media/libeffects/lvm/tests/EffectTestHelper.cpp b/media/libeffects/lvm/tests/EffectTestHelper.cpp
new file mode 100644
index 0000000..625c15a
--- /dev/null
+++ b/media/libeffects/lvm/tests/EffectTestHelper.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright 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.
+ */
+
+#include "EffectTestHelper.h"
+extern audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM;
+
+namespace android {
+
+void EffectTestHelper::createEffect() {
+ int status = AUDIO_EFFECT_LIBRARY_INFO_SYM.create_effect(mUuid, 1, 1, &mEffectHandle);
+ ASSERT_EQ(status, 0) << "create_effect returned an error " << status;
+}
+
+void EffectTestHelper::releaseEffect() {
+ int status = AUDIO_EFFECT_LIBRARY_INFO_SYM.release_effect(mEffectHandle);
+ ASSERT_EQ(status, 0) << "release_effect returned an error " << status;
+}
+
+void EffectTestHelper::setConfig() {
+ effect_config_t config{};
+ config.inputCfg.samplingRate = config.outputCfg.samplingRate = mSampleRate;
+ config.inputCfg.channels = mInChMask;
+ config.outputCfg.channels = mOutChMask;
+ config.inputCfg.format = config.outputCfg.format = AUDIO_FORMAT_PCM_FLOAT;
+
+ int reply = 0;
+ uint32_t replySize = sizeof(reply);
+ int status = (*mEffectHandle)
+ ->command(mEffectHandle, EFFECT_CMD_SET_CONFIG, sizeof(effect_config_t),
+ &config, &replySize, &reply);
+ ASSERT_EQ(status, 0) << "set_config returned an error " << status;
+ ASSERT_EQ(reply, 0) << "set_config reply non zero " << reply;
+
+ status = (*mEffectHandle)
+ ->command(mEffectHandle, EFFECT_CMD_ENABLE, 0, nullptr, &replySize, &reply);
+ ASSERT_EQ(status, 0) << "cmd_enable returned an error " << status;
+ ASSERT_EQ(reply, 0) << "cmd_enable reply non zero " << reply;
+}
+
+void EffectTestHelper::setParam(uint32_t type, uint32_t value) {
+ int reply = 0;
+ uint32_t replySize = sizeof(reply);
+ uint32_t paramData[2] = {type, value};
+ auto effectParam = new effect_param_t[sizeof(effect_param_t) + sizeof(paramData)];
+ memcpy(&effectParam->data[0], ¶mData[0], sizeof(paramData));
+ effectParam->psize = sizeof(paramData[0]);
+ effectParam->vsize = sizeof(paramData[1]);
+ int status = (*mEffectHandle)
+ ->command(mEffectHandle, EFFECT_CMD_SET_PARAM,
+ sizeof(effect_param_t) + sizeof(paramData), effectParam,
+ &replySize, &reply);
+ delete[] effectParam;
+ ASSERT_EQ(status, 0) << "set_param returned an error " << status;
+ ASSERT_EQ(reply, 0) << "set_param reply non zero " << reply;
+}
+
+void EffectTestHelper::process(float* input, float* output) {
+ audio_buffer_t inBuffer = {.frameCount = mFrameCount, .f32 = input};
+ audio_buffer_t outBuffer = {.frameCount = mFrameCount, .f32 = output};
+ for (size_t i = 0; i < mLoopCount; i++) {
+ int status = (*mEffectHandle)->process(mEffectHandle, &inBuffer, &outBuffer);
+ ASSERT_EQ(status, 0) << "process returned an error " << status;
+
+ inBuffer.f32 += mFrameCount * mInChannelCount;
+ outBuffer.f32 += mFrameCount * mOutChannelCount;
+ }
+}
+} // namespace android
diff --git a/media/libeffects/lvm/tests/EffectTestHelper.h b/media/libeffects/lvm/tests/EffectTestHelper.h
new file mode 100644
index 0000000..3854d46
--- /dev/null
+++ b/media/libeffects/lvm/tests/EffectTestHelper.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright 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.
+ */
+
+#pragma once
+
+#include <array>
+#include <audio_utils/channels.h>
+#include <audio_utils/primitives.h>
+#include <climits>
+#include <cstdlib>
+#include <gtest/gtest.h>
+#include <hardware/audio_effect.h>
+#include <log/log.h>
+#include <random>
+#include <stdint.h>
+#include <system/audio.h>
+#include <vector>
+
+namespace android {
+template <typename T>
+static float computeSnr(const T* ref, const T* tst, size_t count) {
+ double signal{};
+ double noise{};
+
+ for (size_t i = 0; i < count; ++i) {
+ const double value(ref[i]);
+ const double diff(tst[i] - value);
+ signal += value * value;
+ noise += diff * diff;
+ }
+ // Initialized to large value to handle
+ // cases where ref and tst match exactly
+ float snr = FLT_MAX;
+ if (signal > 0.0f && noise > 0.0f) {
+ snr = 10.f * log(signal / noise);
+ }
+ return snr;
+}
+
+class EffectTestHelper {
+ public:
+ EffectTestHelper(const effect_uuid_t* uuid, size_t inChMask, size_t outChMask,
+ size_t sampleRate, size_t frameCount, size_t loopCount)
+ : mUuid(uuid),
+ mInChMask(inChMask),
+ mInChannelCount(audio_channel_count_from_out_mask(mInChMask)),
+ mOutChMask(outChMask),
+ mOutChannelCount(audio_channel_count_from_out_mask(mOutChMask)),
+ mSampleRate(sampleRate),
+ mFrameCount(frameCount),
+ mLoopCount(loopCount) {}
+ void createEffect();
+ void releaseEffect();
+ void setConfig();
+ void setParam(uint32_t type, uint32_t val);
+ void process(float* input, float* output);
+
+ // Corresponds to SNR for 1 bit difference between two int16_t signals
+ static constexpr float kSNRThreshold = 90.308998;
+
+ static constexpr audio_channel_mask_t kChMasks[] = {
+ AUDIO_CHANNEL_OUT_MONO, AUDIO_CHANNEL_OUT_STEREO,
+ AUDIO_CHANNEL_OUT_2POINT1, AUDIO_CHANNEL_OUT_2POINT0POINT2,
+ AUDIO_CHANNEL_OUT_QUAD, AUDIO_CHANNEL_OUT_QUAD_BACK,
+ AUDIO_CHANNEL_OUT_QUAD_SIDE, AUDIO_CHANNEL_OUT_SURROUND,
+ AUDIO_CHANNEL_INDEX_MASK_4, AUDIO_CHANNEL_OUT_2POINT1POINT2,
+ AUDIO_CHANNEL_OUT_3POINT0POINT2, AUDIO_CHANNEL_OUT_PENTA,
+ AUDIO_CHANNEL_INDEX_MASK_5, AUDIO_CHANNEL_OUT_3POINT1POINT2,
+ AUDIO_CHANNEL_OUT_5POINT1, AUDIO_CHANNEL_OUT_5POINT1_BACK,
+ AUDIO_CHANNEL_OUT_5POINT1_SIDE, AUDIO_CHANNEL_INDEX_MASK_6,
+ AUDIO_CHANNEL_OUT_6POINT1, AUDIO_CHANNEL_INDEX_MASK_7,
+ AUDIO_CHANNEL_OUT_5POINT1POINT2, AUDIO_CHANNEL_OUT_7POINT1,
+ AUDIO_CHANNEL_INDEX_MASK_8, AUDIO_CHANNEL_INDEX_MASK_9,
+ AUDIO_CHANNEL_INDEX_MASK_10, AUDIO_CHANNEL_INDEX_MASK_11,
+ AUDIO_CHANNEL_INDEX_MASK_12, AUDIO_CHANNEL_INDEX_MASK_13,
+ AUDIO_CHANNEL_INDEX_MASK_14, AUDIO_CHANNEL_INDEX_MASK_15,
+ AUDIO_CHANNEL_INDEX_MASK_16, AUDIO_CHANNEL_INDEX_MASK_17,
+ AUDIO_CHANNEL_INDEX_MASK_18, AUDIO_CHANNEL_INDEX_MASK_19,
+ AUDIO_CHANNEL_INDEX_MASK_20, AUDIO_CHANNEL_INDEX_MASK_21,
+ AUDIO_CHANNEL_INDEX_MASK_22, AUDIO_CHANNEL_INDEX_MASK_23,
+ AUDIO_CHANNEL_INDEX_MASK_24,
+ };
+
+ static constexpr size_t kNumChMasks = std::size(kChMasks);
+
+ static constexpr size_t kSampleRates[] = {8000, 11025, 12000, 16000, 22050, 24000, 32000,
+ 44100, 48000, 88200, 96000, 176400, 192000};
+
+ static constexpr size_t kNumSampleRates = std::size(kSampleRates);
+
+ static constexpr size_t kFrameCounts[] = {4, 2048};
+
+ static constexpr size_t kNumFrameCounts = std::size(kFrameCounts);
+
+ static constexpr size_t kLoopCounts[] = {1, 4};
+
+ static constexpr size_t kNumLoopCounts = std::size(kLoopCounts);
+
+ private:
+ const effect_uuid_t* mUuid;
+ const size_t mInChMask;
+ const size_t mInChannelCount;
+ const size_t mOutChMask;
+ const size_t mOutChannelCount;
+ const size_t mSampleRate;
+ const size_t mFrameCount;
+ const size_t mLoopCount;
+ effect_handle_t mEffectHandle{};
+};
+} // namespace android
diff --git a/media/libeffects/lvm/tests/reverb_test.cpp b/media/libeffects/lvm/tests/reverb_test.cpp
index cecc975..dfb6970 100644
--- a/media/libeffects/lvm/tests/reverb_test.cpp
+++ b/media/libeffects/lvm/tests/reverb_test.cpp
@@ -212,7 +212,9 @@
printUsage();
return EXIT_FAILURE;
}
-
+ for (int i = 1; i < argc; i++) {
+ printf("%s ", argv[i]);
+ }
reverbConfigParams_t revConfigParams{}; // default initialize
const char* inputFile = nullptr;
const char* outputFile = nullptr;
@@ -312,9 +314,6 @@
config.inputCfg.samplingRate = config.outputCfg.samplingRate = revConfigParams.sampleRate;
config.inputCfg.channels = config.outputCfg.channels = revConfigParams.chMask;
config.inputCfg.format = config.outputCfg.format = AUDIO_FORMAT_PCM_FLOAT;
- if (AUDIO_CHANNEL_OUT_MONO == revConfigParams.chMask) {
- config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
- }
if (int status = reverbCreateEffect(&effectHandle, &config, sessionId, ioId,
revConfigParams.auxiliary);
status != 0) {
@@ -346,19 +345,11 @@
const int ioChannelCount = revConfigParams.fChannels;
const int ioFrameSize = ioChannelCount * sizeof(short);
const int maxChannelCount = std::max(channelCount, ioChannelCount);
- /*
- * Mono input will be converted to 2 channels internally in the process call
- * by copying the same data into the second channel.
- * Hence when channelCount is 1, output buffer should be allocated for
- * 2 channels. The outChannelCount takes care of allocation of sufficient
- * memory for the output buffer.
- */
- const int outChannelCount = (channelCount == 1 ? 2 : channelCount);
std::vector<short> in(frameLength * maxChannelCount);
- std::vector<short> out(frameLength * outChannelCount);
+ std::vector<short> out(frameLength * maxChannelCount);
std::vector<float> floatIn(frameLength * channelCount);
- std::vector<float> floatOut(frameLength * outChannelCount);
+ std::vector<float> floatOut(frameLength * channelCount);
int frameCounter = 0;
@@ -392,11 +383,11 @@
#else
memcpy(floatOut.data(), floatIn.data(), frameLength * frameSize);
#endif
- memcpy_to_i16_from_float(out.data(), floatOut.data(), frameLength * outChannelCount);
+ memcpy_to_i16_from_float(out.data(), floatOut.data(), frameLength * channelCount);
- if (ioChannelCount != outChannelCount) {
- adjust_channels(out.data(), outChannelCount, out.data(), ioChannelCount, sizeof(short),
- frameLength * outChannelCount * sizeof(short));
+ if (ioChannelCount != channelCount) {
+ adjust_channels(out.data(), channelCount, out.data(), ioChannelCount, sizeof(short),
+ frameLength * channelCount * sizeof(short));
}
(void)fwrite(out.data(), ioFrameSize, frameLength, outputFp.get());
frameCounter += frameLength;
diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
index 4489e81..290a7b1 100644
--- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
@@ -33,6 +33,7 @@
#include "EffectReverb.h"
// from Reverb/lib
#include "LVREV.h"
+#include "VectorArithmetic.h"
// effect_handle_t interface implementation for reverb
extern "C" const struct effect_interface_s gReverbInterface;
@@ -332,6 +333,7 @@
//----------------------------------------------------------------------------
int process(effect_buffer_t* pIn, effect_buffer_t* pOut, int frameCount, ReverbContext* pContext) {
int channels = audio_channel_count_from_out_mask(pContext->config.inputCfg.channels);
+ int outChannels = audio_channel_count_from_out_mask(pContext->config.outputCfg.channels);
LVREV_ReturnStatus_en LvmStatus = LVREV_SUCCESS; /* Function call status */
// Reverb only effects the stereo channels in multichannel source.
@@ -454,33 +456,49 @@
}
}
- if (channels > 2) {
+ if (outChannels > 2) {
// Accumulate if required
if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
for (int i = 0; i < frameCount; i++) {
- pOut[channels * i] += pContext->OutFrames[FCC_2 * i];
- pOut[channels * i + 1] += pContext->OutFrames[FCC_2 * i + 1];
+ pOut[outChannels * i] += pContext->OutFrames[FCC_2 * i];
+ pOut[outChannels * i + 1] += pContext->OutFrames[FCC_2 * i + 1];
}
} else {
for (int i = 0; i < frameCount; i++) {
- pOut[channels * i] = pContext->OutFrames[FCC_2 * i];
- pOut[channels * i + 1] = pContext->OutFrames[FCC_2 * i + 1];
+ pOut[outChannels * i] = pContext->OutFrames[FCC_2 * i];
+ pOut[outChannels * i + 1] = pContext->OutFrames[FCC_2 * i + 1];
}
}
- for (int i = 0; i < frameCount; i++) {
- for (int j = FCC_2; j < channels; j++) {
- pOut[channels * i + j] = pIn[channels * i + j];
+ if (!pContext->auxiliary) {
+ for (int i = 0; i < frameCount; i++) {
+ // channels and outChannels are expected to be same.
+ for (int j = FCC_2; j < outChannels; j++) {
+ pOut[outChannels * i + j] = pIn[outChannels * i + j];
+ }
}
}
} else {
if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
- for (int i = 0; i < frameCount * FCC_2; i++) {
- pOut[i] += pContext->OutFrames[i];
+ if (outChannels == FCC_1) {
+ for (int i = 0; i < frameCount; i++) {
+ pOut[i] +=
+ ((pContext->OutFrames[i * FCC_2] + pContext->OutFrames[i * FCC_2 + 1]) *
+ 0.5f);
+ }
+ } else {
+ for (int i = 0; i < frameCount * FCC_2; i++) {
+ pOut[i] += pContext->OutFrames[i];
+ }
}
} else {
- memcpy(pOut, pContext->OutFrames, frameCount * sizeof(*pOut) * FCC_2);
+ if (outChannels == FCC_1) {
+ From2iToMono_Float((const process_buffer_t*)pContext->OutFrames, pOut, frameCount);
+ } else {
+ memcpy(pOut, pContext->OutFrames, frameCount * sizeof(*pOut) * FCC_2);
+ }
}
}
+
return 0;
} /* end process */
@@ -498,25 +516,6 @@
void Reverb_free(ReverbContext* pContext) {
LVREV_ReturnStatus_en LvmStatus = LVREV_SUCCESS; /* Function call status */
- LVREV_MemoryTable_st MemTab;
-
- /* Free the algorithm memory */
- LvmStatus = LVREV_GetMemoryTable(pContext->hInstance, &MemTab, LVM_NULL);
-
- LVM_ERROR_CHECK(LvmStatus, "LVM_GetMemoryTable", "Reverb_free")
-
- for (int i = 0; i < LVM_NR_MEMORY_REGIONS; i++) {
- if (MemTab.Region[i].Size != 0) {
- if (MemTab.Region[i].pBaseAddress != NULL) {
- free(MemTab.Region[i].pBaseAddress);
- } else {
- ALOGV("\tLVM_ERROR : free() - trying to free with NULL pointer %" PRIu32
- " bytes "
- "for region %u at %p ERROR\n",
- MemTab.Region[i].Size, i, MemTab.Region[i].pBaseAddress);
- }
- }
- }
LvmStatus = LVREV_FreeInstance(pContext->hInstance);
LVM_ERROR_CHECK(LvmStatus, "LVREV_FreeInstance", "Reverb_free")
@@ -549,7 +548,7 @@
CHECK_ARG((pContext->auxiliary && pConfig->inputCfg.channels == AUDIO_CHANNEL_OUT_MONO) ||
((!pContext->auxiliary) && (inputChannels <= LVM_MAX_CHANNELS)));
int outputChannels = audio_channel_count_from_out_mask(pConfig->outputCfg.channels);
- CHECK_ARG(outputChannels >= FCC_2 && outputChannels <= LVM_MAX_CHANNELS);
+ CHECK_ARG(outputChannels <= LVM_MAX_CHANNELS);
CHECK_ARG(pConfig->outputCfg.accessMode == EFFECT_BUFFER_ACCESS_WRITE ||
pConfig->outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE);
CHECK_ARG(pConfig->inputCfg.format == EFFECT_BUFFER_FORMAT);
@@ -659,65 +658,17 @@
LVREV_ReturnStatus_en LvmStatus = LVREV_SUCCESS; /* Function call status */
LVREV_ControlParams_st params; /* Control Parameters */
LVREV_InstanceParams_st InstParams; /* Instance parameters */
- LVREV_MemoryTable_st MemTab; /* Memory allocation table */
- bool bMallocFailure = LVM_FALSE;
/* Set the capabilities */
InstParams.MaxBlockSize = MAX_CALL_SIZE;
InstParams.SourceFormat = LVM_STEREO; // Max format, could be mono during process
InstParams.NumDelays = LVREV_DELAYLINES_4;
- /* Allocate memory, forcing alignment */
- LvmStatus = LVREV_GetMemoryTable(LVM_NULL, &MemTab, &InstParams);
-
- LVM_ERROR_CHECK(LvmStatus, "LVREV_GetMemoryTable", "Reverb_init")
- if (LvmStatus != LVREV_SUCCESS) return -EINVAL;
-
- ALOGV("\tCreateInstance Successfully called LVM_GetMemoryTable\n");
-
- /* Allocate memory */
- for (int i = 0; i < LVM_NR_MEMORY_REGIONS; i++) {
- if (MemTab.Region[i].Size != 0) {
- MemTab.Region[i].pBaseAddress = calloc(1, MemTab.Region[i].Size);
-
- if (MemTab.Region[i].pBaseAddress == LVM_NULL) {
- ALOGV("\tLVREV_ERROR :Reverb_init CreateInstance Failed to allocate %" PRIu32
- " bytes for region %u\n",
- MemTab.Region[i].Size, i);
- bMallocFailure = LVM_TRUE;
- } else {
- ALOGV("\tReverb_init CreateInstance allocate %" PRIu32
- " bytes for region %u at %p\n",
- MemTab.Region[i].Size, i, MemTab.Region[i].pBaseAddress);
- }
- }
- }
-
- /* If one or more of the memory regions failed to allocate, free the regions that were
- * succesfully allocated and return with an error
- */
- if (bMallocFailure == LVM_TRUE) {
- for (int i = 0; i < LVM_NR_MEMORY_REGIONS; i++) {
- if (MemTab.Region[i].pBaseAddress == LVM_NULL) {
- ALOGV("\tLVM_ERROR :Reverb_init CreateInstance Failed to allocate %" PRIu32
- " bytes for region %u - Not freeing\n",
- MemTab.Region[i].Size, i);
- } else {
- ALOGV("\tLVM_ERROR :Reverb_init CreateInstance Failed: but allocated %" PRIu32
- " bytes for region %u at %p- free\n",
- MemTab.Region[i].Size, i, MemTab.Region[i].pBaseAddress);
- free(MemTab.Region[i].pBaseAddress);
- }
- }
- return -EINVAL;
- }
- ALOGV("\tReverb_init CreateInstance Successfully malloc'd memory\n");
-
/* Initialise */
pContext->hInstance = LVM_NULL;
/* Init sets the instance handle */
- LvmStatus = LVREV_GetInstanceHandle(&pContext->hInstance, &MemTab, &InstParams);
+ LvmStatus = LVREV_GetInstanceHandle(&pContext->hInstance, &InstParams);
LVM_ERROR_CHECK(LvmStatus, "LVM_GetInstanceHandle", "Reverb_init")
if (LvmStatus != LVREV_SUCCESS) return -EINVAL;
diff --git a/media/libeffects/preprocessing/Android.bp b/media/libeffects/preprocessing/Android.bp
index eb3ce34..87ed8b6 100644
--- a/media/libeffects/preprocessing/Android.bp
+++ b/media/libeffects/preprocessing/Android.bp
@@ -22,6 +22,7 @@
name: "libaudiopreprocessing",
vendor: true,
relative_install_path: "soundfx",
+ host_supported: true,
srcs: ["PreProcessing.cpp"],
local_include_dirs: [
".",
@@ -47,4 +48,9 @@
"libhardware_headers",
"libwebrtc_absl_headers",
],
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
}
diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp
index 03ccc34..3b0b6d6 100644
--- a/media/libeffects/preprocessing/PreProcessing.cpp
+++ b/media/libeffects/preprocessing/PreProcessing.cpp
@@ -670,8 +670,8 @@
return 0;
}
-int NsGetParameter(preproc_effect_t* effect __unused, void* pParam __unused,
- uint32_t* pValueSize __unused, void* pValue __unused) {
+int NsGetParameter(preproc_effect_t* /*effect __unused*/, void* /*pParam __unused*/,
+ uint32_t* /*pValueSize __unused*/, void* /*pValue __unused*/) {
int status = 0;
return status;
}
@@ -910,7 +910,7 @@
session->apm = NULL;
delete session->inBuf;
session->inBuf = NULL;
- delete session->outBuf;
+ free(session->outBuf);
session->outBuf = NULL;
delete session->revBuf;
session->revBuf = NULL;
@@ -1551,7 +1551,7 @@
}
int PreProcessingFx_ProcessReverse(effect_handle_t self, audio_buffer_t* inBuffer,
- audio_buffer_t* outBuffer __unused) {
+ audio_buffer_t* outBuffer) {
preproc_effect_t* effect = (preproc_effect_t*)self;
if (effect == NULL) {
diff --git a/media/libeffects/preprocessing/tests/Android.bp b/media/libeffects/preprocessing/tests/Android.bp
index 8848e79..6413945 100644
--- a/media/libeffects/preprocessing/tests/Android.bp
+++ b/media/libeffects/preprocessing/tests/Android.bp
@@ -13,6 +13,8 @@
cc_test {
name: "AudioPreProcessingTest",
vendor: true,
+ host_supported: true,
+ gtest: false,
srcs: ["PreProcessingTest.cpp"],
shared_libs: [
"libaudioutils",
@@ -27,7 +29,11 @@
"libaudioeffects",
"libhardware_headers",
],
- gtest: false,
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
}
cc_test {
diff --git a/media/libeffects/preprocessing/tests/PreProcessingTest.cpp b/media/libeffects/preprocessing/tests/PreProcessingTest.cpp
index 5f223c9..e0025fe 100644
--- a/media/libeffects/preprocessing/tests/PreProcessingTest.cpp
+++ b/media/libeffects/preprocessing/tests/PreProcessingTest.cpp
@@ -24,6 +24,7 @@
#include <audio_effects/effect_agc.h>
#include <audio_effects/effect_agc2.h>
#include <audio_effects/effect_ns.h>
+#include <audio_utils/channels.h>
#include <log/log.h>
// This is the only symbol that needs to be imported
@@ -55,7 +56,9 @@
ARG_NS_LVL,
ARG_AGC2_GAIN,
ARG_AGC2_LVL,
- ARG_AGC2_SAT_MGN
+ ARG_AGC2_SAT_MGN,
+ ARG_FILE_CHANNELS,
+ ARG_MONO_MODE
};
struct preProcConfigParams_t {
@@ -68,6 +71,8 @@
float agc2SaturationMargin = 2.f; // in dB
int agc2Level = 0; // either kRms(0) or kPeak(1)
int aecDelay = 0; // in ms
+ int fileChannels = 1;
+ int monoMode = 0;
};
const effect_uuid_t kPreProcUuids[PREPROC_NUM_EFFECTS] = {
@@ -106,7 +111,7 @@
printf("\n Prints this usage information");
printf("\n --fs <sampling_freq>");
printf("\n Sampling frequency in Hz, default 16000.");
- printf("\n -ch_mask <channel_mask>\n");
+ printf("\n --ch_mask <channel_mask>\n");
printf("\n 0 - AUDIO_CHANNEL_IN_MONO");
printf("\n 1 - AUDIO_CHANNEL_IN_STEREO");
printf("\n 2 - AUDIO_CHANNEL_IN_FRONT_BACK");
@@ -144,6 +149,10 @@
printf("\n AGC Adaptive Digital Saturation Margin in dB, default value 2dB");
printf("\n --aec_delay <delay>");
printf("\n AEC delay value in ms, default value 0ms");
+ printf("\n --fch <fileChannels>");
+ printf("\n number of channels in the input file");
+ printf("\n --mono <Mono Mode>");
+ printf("\n Mode to make data of all channels the same as first channel");
printf("\n");
}
@@ -189,10 +198,17 @@
printUsage();
return EXIT_FAILURE;
}
+
+ // Print the arguments passed
+ for (int i = 1; i < argc; i++) {
+ printf("%s ", argv[i]);
+ }
+
const char* inputFile = nullptr;
const char* outputFile = nullptr;
const char* farFile = nullptr;
int effectEn[PREPROC_NUM_EFFECTS] = {0};
+ struct preProcConfigParams_t preProcCfgParams {};
const option long_opts[] = {
{"help", no_argument, nullptr, ARG_HELP},
@@ -212,9 +228,10 @@
{"agc", no_argument, &effectEn[PREPROC_AGC], 1},
{"agc2", no_argument, &effectEn[PREPROC_AGC2], 1},
{"ns", no_argument, &effectEn[PREPROC_NS], 1},
+ {"fch", required_argument, nullptr, ARG_FILE_CHANNELS},
+ {"mono", no_argument, &preProcCfgParams.monoMode, 1},
{nullptr, 0, nullptr, 0},
};
- struct preProcConfigParams_t preProcCfgParams {};
while (true) {
const int opt = getopt_long(argc, (char* const*)argv, "i:o:", long_opts, nullptr);
@@ -279,6 +296,14 @@
preProcCfgParams.nsLevel = atoi(optarg);
break;
}
+ case ARG_FILE_CHANNELS: {
+ preProcCfgParams.fileChannels = atoi(optarg);
+ break;
+ }
+ case ARG_MONO_MODE: {
+ preProcCfgParams.monoMode = 1;
+ break;
+ }
default:
break;
}
@@ -402,16 +427,28 @@
// Process Call
const int frameLength = (int)(preProcCfgParams.samplingFreq * kTenMilliSecVal);
const int ioChannelCount = audio_channel_count_from_in_mask(preProcCfgParams.chMask);
+ const int fileChannelCount = preProcCfgParams.fileChannels;
const int ioFrameSize = ioChannelCount * sizeof(short);
+ const int inFrameSize = fileChannelCount * sizeof(short);
int frameCounter = 0;
while (true) {
std::vector<short> in(frameLength * ioChannelCount);
std::vector<short> out(frameLength * ioChannelCount);
std::vector<short> farIn(frameLength * ioChannelCount);
- size_t samplesRead = fread(in.data(), ioFrameSize, frameLength, inputFp.get());
+ size_t samplesRead = fread(in.data(), inFrameSize, frameLength, inputFp.get());
if (samplesRead == 0) {
break;
}
+ if (fileChannelCount != ioChannelCount) {
+ adjust_channels(in.data(), fileChannelCount, in.data(), ioChannelCount, sizeof(short),
+ frameLength * inFrameSize);
+ if (preProcCfgParams.monoMode == 1) {
+ for (int i = 0; i < frameLength; ++i) {
+ auto* fp = &in[i * ioChannelCount];
+ std::fill(fp + 1, fp + ioChannelCount, *fp); // replicate ch 0
+ }
+ }
+ }
audio_buffer_t inputBuffer, outputBuffer;
audio_buffer_t farInBuffer{};
inputBuffer.frameCount = samplesRead;
@@ -420,10 +457,21 @@
outputBuffer.s16 = out.data();
if (farFp != nullptr) {
- samplesRead = fread(farIn.data(), ioFrameSize, frameLength, farFp.get());
+ samplesRead = fread(farIn.data(), inFrameSize, frameLength, farFp.get());
if (samplesRead == 0) {
break;
}
+ if (fileChannelCount != ioChannelCount) {
+ adjust_channels(farIn.data(), fileChannelCount, farIn.data(), ioChannelCount,
+ sizeof(short), frameLength * inFrameSize);
+ if (preProcCfgParams.monoMode == 1) {
+ for (int i = 0; i < frameLength; ++i) {
+ auto* fp = &farIn[i * ioChannelCount];
+ std::fill(fp + 1, fp + ioChannelCount, *fp); // replicate ch 0
+ }
+ }
+ }
+
farInBuffer.frameCount = samplesRead;
farInBuffer.s16 = farIn.data();
}
@@ -458,8 +506,12 @@
}
}
if (outputFp != nullptr) {
+ if (fileChannelCount != ioChannelCount) {
+ adjust_channels(out.data(), ioChannelCount, out.data(), fileChannelCount,
+ sizeof(short), frameLength * ioFrameSize);
+ }
size_t samplesWritten =
- fwrite(out.data(), ioFrameSize, outputBuffer.frameCount, outputFp.get());
+ fwrite(out.data(), inFrameSize, outputBuffer.frameCount, outputFp.get());
if (samplesWritten != outputBuffer.frameCount) {
ALOGE("\nError: Output file writing failed");
break;
diff --git a/media/libeffects/preprocessing/tests/build_and_run_all_unit_tests.sh b/media/libeffects/preprocessing/tests/build_and_run_all_unit_tests.sh
new file mode 100755
index 0000000..942f2ec
--- /dev/null
+++ b/media/libeffects/preprocessing/tests/build_and_run_all_unit_tests.sh
@@ -0,0 +1,115 @@
+#!/bin/bash
+#
+# Run tests in this directory.
+#
+
+if [ -z "$ANDROID_BUILD_TOP" ]; then
+ echo "Android build environment not set"
+ exit -1
+fi
+
+# ensure we have mm
+. $ANDROID_BUILD_TOP/build/envsetup.sh
+
+mm -j
+
+echo "waiting for device"
+
+adb root && adb wait-for-device remount
+
+# location of test files
+testdir="/data/local/tmp/AudioPreProcessingTest"
+
+echo "========================================"
+echo "testing PreProcessing modules"
+adb shell mkdir -p $testdir
+adb push $ANDROID_BUILD_TOP/frameworks/av/media/libeffects/res/raw/sinesweepraw.raw $testdir
+adb push $OUT/testcases/snr/arm64/snr $testdir
+
+E_VAL=1
+if [ -z "$1" ]
+then
+ cmds=("adb push $OUT/testcases/AudioPreProcessingTest/arm64/AudioPreProcessingTest $testdir"
+ "adb push $OUT/testcases/AudioPreProcessingTest/arm/AudioPreProcessingTest $testdir"
+)
+elif [ "$1" == "32" ]
+then
+ cmds="adb push $OUT/testcases/AudioPreProcessingTest/arm/AudioPreProcessingTest $testdir"
+elif [ "$1" == "64" ]
+then
+ cmds="adb push $OUT/testcases/AudioPreProcessingTest/arm64/AudioPreProcessingTest $testdir"
+else
+ echo ""
+ echo "Invalid \"val\""
+ echo "Usage:"
+ echo " "$0" [val]"
+ echo " where, val can be either 32 or 64."
+ echo ""
+ echo " If val is not specified then both 32 bit and 64 bit binaries"
+ echo " are tested."
+ exit $E_VAL
+fi
+
+flags_arr=(
+ "--agc --mono"
+ "--ns --mono"
+ "--agc2 --mono"
+ "--aec --mono"
+)
+
+fs_arr=(
+ 8000
+ 16000
+ 24000
+ 32000
+ 48000
+)
+
+# run multichannel effects at different configs, saving only the mono channel
+error_count=0
+test_count=0
+for cmd in "${cmds[@]}"
+do
+ $cmd
+ for flags in "${flags_arr[@]}"
+ do
+ for fs in ${fs_arr[*]}
+ do
+ for chMask in {0..7}
+ do
+ adb shell $testdir/AudioPreProcessingTest $flags \
+ --i $testdir/sinesweepraw.raw --far $testdir/sinesweepraw.raw \
+ --output $testdir/sinesweep_$((chMask))_$((fs)).raw --ch_mask $chMask \
+ --fs $fs --fch 1
+
+ shell_ret=$?
+ if [ $shell_ret -ne 0 ]; then
+ echo "error shell_ret here is zero: $shell_ret"
+ ((++error_count))
+ fi
+
+
+ # single channel files should be identical to higher channel
+ # computation (first channel).
+ if [[ "$chMask" -gt 1 ]]
+ then
+ adb shell cmp $testdir/sinesweep_1_$((fs)).raw \
+ $testdir/sinesweep_$((chMask))_$((fs)).raw
+ fi
+
+ # cmp return EXIT_FAILURE on mismatch.
+ shell_ret=$?
+ if [ $shell_ret -ne 0 ]; then
+ echo "error: $shell_ret"
+ ((++error_count))
+ fi
+ ((++test_count))
+ done
+ done
+ done
+done
+
+adb shell rm -r $testdir
+echo "$test_count tests performed"
+echo "$error_count errors"
+exit $error_count
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 0223cfd..9e33610 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -359,6 +359,7 @@
"libaudioclient",
"libmedia_codeclist",
"libmedia_omx",
+ "media_permission-aidl-cpp",
],
export_shared_lib_headers: [
@@ -367,14 +368,17 @@
"libandroidicu",
//"libsonivox",
"libmedia_omx",
+ "media_permission-aidl-cpp",
],
static_libs: [
"resourcemanager_aidl_interface-ndk_platform",
+ "media_permission-aidl-cpp",
],
export_static_lib_headers: [
"resourcemanager_aidl_interface-ndk_platform",
+ "media_permission-aidl-cpp",
],
export_include_dirs: [
diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp
index 11005c6..0f189ee 100644
--- a/media/libmedia/IMediaPlayerService.cpp
+++ b/media/libmedia/IMediaPlayerService.cpp
@@ -35,6 +35,8 @@
namespace android {
+using media::permission::Identity;
+
enum {
CREATE = IBinder::FIRST_CALL_TRANSACTION,
CREATE_MEDIA_RECORDER,
@@ -63,22 +65,22 @@
virtual sp<IMediaPlayer> create(
const sp<IMediaPlayerClient>& client, audio_session_t audioSessionId,
- const std::string opPackageName) {
+ const Identity& identity) {
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
data.writeStrongBinder(IInterface::asBinder(client));
data.writeInt32(audioSessionId);
- data.writeCString(opPackageName.c_str());
+ data.writeParcelable(identity);
remote()->transact(CREATE, data, &reply);
return interface_cast<IMediaPlayer>(reply.readStrongBinder());
}
- virtual sp<IMediaRecorder> createMediaRecorder(const String16 &opPackageName)
+ virtual sp<IMediaRecorder> createMediaRecorder(const Identity& identity)
{
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
- data.writeString16(opPackageName);
+ data.writeParcelable(identity);
remote()->transact(CREATE_MEDIA_RECORDER, data, &reply);
return interface_cast<IMediaRecorder>(reply.readStrongBinder());
}
@@ -129,19 +131,23 @@
sp<IMediaPlayerClient> client =
interface_cast<IMediaPlayerClient>(data.readStrongBinder());
audio_session_t audioSessionId = (audio_session_t) data.readInt32();
- const char* opPackageName = data.readCString();
- if (opPackageName == nullptr) {
- return FAILED_TRANSACTION;
+ Identity identity;
+ status_t status = data.readParcelable(&identity);
+ if (status != NO_ERROR) {
+ return status;
}
- std::string opPackageNameStr(opPackageName);
- sp<IMediaPlayer> player = create(client, audioSessionId, opPackageNameStr);
+ sp<IMediaPlayer> player = create(client, audioSessionId, identity);
reply->writeStrongBinder(IInterface::asBinder(player));
return NO_ERROR;
} break;
case CREATE_MEDIA_RECORDER: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
- const String16 opPackageName = data.readString16();
- sp<IMediaRecorder> recorder = createMediaRecorder(opPackageName);
+ Identity identity;
+ status_t status = data.readParcelable(&identity);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ sp<IMediaRecorder> recorder = createMediaRecorder(identity);
reply->writeStrongBinder(IInterface::asBinder(recorder));
return NO_ERROR;
} break;
diff --git a/media/libmedia/include/media/IMediaPlayerService.h b/media/libmedia/include/media/IMediaPlayerService.h
index a4207eb..243e9c7 100644
--- a/media/libmedia/include/media/IMediaPlayerService.h
+++ b/media/libmedia/include/media/IMediaPlayerService.h
@@ -27,6 +27,7 @@
#include <media/IMediaPlayerClient.h>
#include <media/IMediaMetadataRetriever.h>
+#include <android/media/permission/Identity.h>
#include <string>
@@ -46,11 +47,13 @@
public:
DECLARE_META_INTERFACE(MediaPlayerService);
- virtual sp<IMediaRecorder> createMediaRecorder(const String16 &opPackageName) = 0;
+ virtual sp<IMediaRecorder> createMediaRecorder(
+ const android::media::permission::Identity &identity) = 0;
virtual sp<IMediaMetadataRetriever> createMetadataRetriever() = 0;
virtual sp<IMediaPlayer> create(const sp<IMediaPlayerClient>& client,
audio_session_t audioSessionId = AUDIO_SESSION_ALLOCATE,
- const std::string opPackage = "") = 0;
+ const android::media::permission::Identity& identity =
+ android::media::permission::Identity()) = 0;
virtual sp<IMediaCodecList> getCodecList() const = 0;
// Connects to a remote display.
diff --git a/media/libmedia/include/media/MediaRecorderBase.h b/media/libmedia/include/media/MediaRecorderBase.h
index d9a7efb..b5325ce 100644
--- a/media/libmedia/include/media/MediaRecorderBase.h
+++ b/media/libmedia/include/media/MediaRecorderBase.h
@@ -21,6 +21,7 @@
#include <media/AudioSystem.h>
#include <media/MicrophoneInfo.h>
#include <media/mediarecorder.h>
+#include <android/media/permission/Identity.h>
#include <system/audio.h>
@@ -33,8 +34,8 @@
struct PersistentSurface;
struct MediaRecorderBase {
- MediaRecorderBase(const String16 &opPackageName)
- : mOpPackageName(opPackageName) {}
+ explicit MediaRecorderBase(const media::permission::Identity &client)
+ : mClient(client) {}
virtual ~MediaRecorderBase() {}
virtual status_t init() = 0;
@@ -83,7 +84,7 @@
protected:
- String16 mOpPackageName;
+ media::permission::Identity mClient;
private:
MediaRecorderBase(const MediaRecorderBase &);
diff --git a/media/libmedia/include/media/mediaplayer.h b/media/libmedia/include/media/mediaplayer.h
index 71c0bc5..fbba398 100644
--- a/media/libmedia/include/media/mediaplayer.h
+++ b/media/libmedia/include/media/mediaplayer.h
@@ -29,6 +29,7 @@
#include <media/IMediaPlayer.h>
#include <media/IMediaDeathNotifier.h>
#include <media/IStreamSource.h>
+#include <android/media/permission/Identity.h>
#include <utils/KeyedVector.h>
#include <utils/String8.h>
@@ -211,7 +212,8 @@
public virtual IMediaDeathNotifier
{
public:
- MediaPlayer(const std::string opPackageName = "");
+ explicit MediaPlayer(const android::media::permission::Identity& mIdentity =
+ android::media::permission::Identity());
~MediaPlayer();
void died();
void disconnect();
@@ -315,7 +317,7 @@
float mSendLevel;
struct sockaddr_in mRetransmitEndpoint;
bool mRetransmitEndpointValid;
- const std::string mOpPackageName;
+ const android::media::permission::Identity mIdentity;
};
}; // namespace android
diff --git a/media/libmedia/include/media/mediarecorder.h b/media/libmedia/include/media/mediarecorder.h
index 84c92f6..96a3293 100644
--- a/media/libmedia/include/media/mediarecorder.h
+++ b/media/libmedia/include/media/mediarecorder.h
@@ -25,6 +25,7 @@
#include <media/IMediaRecorderClient.h>
#include <media/IMediaDeathNotifier.h>
#include <media/MicrophoneInfo.h>
+#include <android/media/permission/Identity.h>
namespace android {
@@ -226,7 +227,7 @@
public virtual IMediaDeathNotifier
{
public:
- MediaRecorder(const String16& opPackageName);
+ explicit MediaRecorder(const media::permission::Identity& identity);
~MediaRecorder();
void died();
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 30c5006..7504787 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -40,8 +40,9 @@
namespace android {
using media::VolumeShaper;
+using media::permission::Identity;
-MediaPlayer::MediaPlayer(const std::string opPackageName) : mOpPackageName(opPackageName)
+MediaPlayer::MediaPlayer(const Identity& identity) : mIdentity(identity)
{
ALOGV("constructor");
mListener = NULL;
@@ -152,7 +153,7 @@
if (url != NULL) {
const sp<IMediaPlayerService> service(getMediaPlayerService());
if (service != 0) {
- sp<IMediaPlayer> player(service->create(this, mAudioSessionId, mOpPackageName));
+ sp<IMediaPlayer> player(service->create(this, mAudioSessionId, mIdentity));
if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
(NO_ERROR != player->setDataSource(httpService, url, headers))) {
player.clear();
@@ -169,7 +170,7 @@
status_t err = UNKNOWN_ERROR;
const sp<IMediaPlayerService> service(getMediaPlayerService());
if (service != 0) {
- sp<IMediaPlayer> player(service->create(this, mAudioSessionId, mOpPackageName));
+ sp<IMediaPlayer> player(service->create(this, mAudioSessionId, mIdentity));
if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
(NO_ERROR != player->setDataSource(fd, offset, length))) {
player.clear();
@@ -185,7 +186,7 @@
status_t err = UNKNOWN_ERROR;
const sp<IMediaPlayerService> service(getMediaPlayerService());
if (service != 0) {
- sp<IMediaPlayer> player(service->create(this, mAudioSessionId, mOpPackageName));
+ sp<IMediaPlayer> player(service->create(this, mAudioSessionId, mIdentity));
if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
(NO_ERROR != player->setDataSource(source))) {
player.clear();
@@ -201,7 +202,7 @@
status_t err = UNKNOWN_ERROR;
const sp<IMediaPlayerService> service(getMediaPlayerService());
if (service != 0) {
- sp<IMediaPlayer> player(service->create(this, mAudioSessionId, mOpPackageName));
+ sp<IMediaPlayer> player(service->create(this, mAudioSessionId, mIdentity));
if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
(NO_ERROR != player->setDataSource(rtpParams))) {
player.clear();
diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp
index e3cd9d8..da2b190 100644
--- a/media/libmedia/mediarecorder.cpp
+++ b/media/libmedia/mediarecorder.cpp
@@ -33,6 +33,8 @@
namespace android {
+using media::permission::Identity;
+
status_t MediaRecorder::setCamera(const sp<hardware::ICamera>& camera,
const sp<ICameraRecordingProxy>& proxy)
{
@@ -758,13 +760,13 @@
return INVALID_OPERATION;
}
-MediaRecorder::MediaRecorder(const String16& opPackageName) : mSurfaceMediaSource(NULL)
+MediaRecorder::MediaRecorder(const Identity &identity) : mSurfaceMediaSource(NULL)
{
ALOGV("constructor");
const sp<IMediaPlayerService> service(getMediaPlayerService());
if (service != NULL) {
- mMediaRecorder = service->createMediaRecorder(opPackageName);
+ mMediaRecorder = service->createMediaRecorder(identity);
}
if (mMediaRecorder != NULL) {
mCurrentState = MEDIA_RECORDER_IDLE;
diff --git a/media/libmedia/tests/mediaplayer/Android.bp b/media/libmedia/tests/mediaplayer/Android.bp
index 0fff7b4..50f35ea 100644
--- a/media/libmedia/tests/mediaplayer/Android.bp
+++ b/media/libmedia/tests/mediaplayer/Android.bp
@@ -39,6 +39,7 @@
"libstagefright",
"libstagefright_foundation",
"libutils",
+ "media_permission-aidl-cpp",
],
compile_multilib: "first",
cflags: [
diff --git a/media/libmediaplayerservice/Android.bp b/media/libmediaplayerservice/Android.bp
index 56c8368..d250976 100644
--- a/media/libmediaplayerservice/Android.bp
+++ b/media/libmediaplayerservice/Android.bp
@@ -35,6 +35,8 @@
"android.hardware.media.c2@1.0",
"android.hardware.media.omx@1.0",
"av-types-aidl-cpp",
+ "media_permission-aidl-cpp",
+ "libaudioclient_aidl_conversion",
"libbase",
"libandroid_net",
"libaudioclient",
@@ -73,9 +75,13 @@
"libstagefright_nuplayer",
"libstagefright_rtsp",
"libstagefright_timedtext",
+ "media_permission-aidl-cpp",
],
- export_shared_lib_headers: ["libmedia"],
+ export_shared_lib_headers: [
+ "libmedia",
+ "media_permission-aidl-cpp",
+ ],
include_dirs: [
"frameworks/av/media/libstagefright/rtsp",
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 1d5ccca..dc4aea5 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -49,6 +49,7 @@
#include <codec2/hidl/client.h>
#include <datasource/HTTPBase.h>
+#include <media/AidlConversion.h>
#include <media/IMediaHTTPService.h>
#include <media/IRemoteDisplay.h>
#include <media/IRemoteDisplayClient.h>
@@ -94,6 +95,7 @@
using android::NOT_ENOUGH_DATA;
using android::Parcel;
using android::media::VolumeShaper;
+using android::media::permission::Identity;
// Max number of entries in the filter.
const int kMaxFilterSize = 64; // I pulled that out of thin air.
@@ -453,14 +455,21 @@
ALOGV("MediaPlayerService destroyed");
}
-sp<IMediaRecorder> MediaPlayerService::createMediaRecorder(const String16 &opPackageName)
+sp<IMediaRecorder> MediaPlayerService::createMediaRecorder(const Identity& identity)
{
- pid_t pid = IPCThreadState::self()->getCallingPid();
- sp<MediaRecorderClient> recorder = new MediaRecorderClient(this, pid, opPackageName);
+ // TODO b/182392769: use identity util
+ Identity verifiedIdentity = identity;
+ verifiedIdentity.uid = VALUE_OR_FATAL(
+ legacy2aidl_uid_t_int32_t(IPCThreadState::self()->getCallingUid()));
+ verifiedIdentity.pid = VALUE_OR_FATAL(
+ legacy2aidl_pid_t_int32_t(IPCThreadState::self()->getCallingPid()));
+ sp<MediaRecorderClient> recorder =
+ new MediaRecorderClient(this, verifiedIdentity);
wp<MediaRecorderClient> w = recorder;
Mutex::Autolock lock(mLock);
mMediaRecorderClients.add(w);
- ALOGV("Create new media recorder client from pid %d", pid);
+ ALOGV("Create new media recorder client from pid %s",
+ verifiedIdentity.toString().c_str());
return recorder;
}
@@ -480,17 +489,21 @@
}
sp<IMediaPlayer> MediaPlayerService::create(const sp<IMediaPlayerClient>& client,
- audio_session_t audioSessionId, std::string opPackageName)
+ audio_session_t audioSessionId, const Identity& identity)
{
- pid_t pid = IPCThreadState::self()->getCallingPid();
int32_t connId = android_atomic_inc(&mNextConnId);
+ // TODO b/182392769: use identity util
+ Identity verifiedIdentity = identity;
+ verifiedIdentity.pid = VALUE_OR_FATAL(
+ legacy2aidl_pid_t_int32_t(IPCThreadState::self()->getCallingPid()));
+ verifiedIdentity.uid = VALUE_OR_FATAL(
+ legacy2aidl_uid_t_int32_t(IPCThreadState::self()->getCallingUid()));
sp<Client> c = new Client(
- this, pid, connId, client, audioSessionId,
- IPCThreadState::self()->getCallingUid(), opPackageName);
+ this, verifiedIdentity, connId, client, audioSessionId);
- ALOGV("Create new client(%d) from pid %d, uid %d, ", connId, pid,
- IPCThreadState::self()->getCallingUid());
+ ALOGV("Create new client(%d) from %s, ", connId,
+ verifiedIdentity.toString().c_str());
wp<Client> w = c;
{
@@ -543,8 +556,8 @@
char buffer[SIZE];
String8 result;
result.append(" Client\n");
- snprintf(buffer, 255, " pid(%d), connId(%d), status(%d), looping(%s)\n",
- mPid, mConnId, mStatus, mLoop?"true": "false");
+ snprintf(buffer, 255, " Identity(%s), connId(%d), status(%d), looping(%s)\n",
+ mIdentity.toString().c_str(), mConnId, mStatus, mLoop?"true": "false");
result.append(buffer);
sp<MediaPlayerBase> p;
@@ -608,7 +621,7 @@
for (int i = 0, n = mMediaRecorderClients.size(); i < n; ++i) {
sp<MediaRecorderClient> c = mMediaRecorderClients[i].promote();
if (c != 0) {
- snprintf(buffer, 255, " MediaRecorderClient pid(%d)\n", c->mPid);
+ snprintf(buffer, 255, " MediaRecorderClient pid(%d)\n", c->mIdentity.pid);
result.append(buffer);
write(fd, result.string(), result.size());
result = "\n";
@@ -731,20 +744,18 @@
}
MediaPlayerService::Client::Client(
- const sp<MediaPlayerService>& service, pid_t pid,
+ const sp<MediaPlayerService>& service, const Identity& identity,
int32_t connId, const sp<IMediaPlayerClient>& client,
- audio_session_t audioSessionId, uid_t uid, const std::string& opPackageName)
- : mOpPackageName(opPackageName)
+ audio_session_t audioSessionId)
+ : mIdentity(identity)
{
ALOGV("Client(%d) constructor", connId);
- mPid = pid;
mConnId = connId;
mService = service;
mClient = client;
mLoop = false;
mStatus = NO_INIT;
mAudioSessionId = audioSessionId;
- mUid = uid;
mRetransmitEndpointValid = false;
mAudioAttributes = NULL;
mListener = new Listener(this);
@@ -757,7 +768,7 @@
MediaPlayerService::Client::~Client()
{
- ALOGV("Client(%d) destructor pid = %d", mConnId, mPid);
+ ALOGV("Client(%d) destructor identity = %s", mConnId, mIdentity.toString().c_str());
mAudioOutput.clear();
wp<Client> client(this);
disconnect();
@@ -770,7 +781,7 @@
void MediaPlayerService::Client::disconnect()
{
- ALOGV("disconnect(%d) from pid %d", mConnId, mPid);
+ ALOGV("disconnect(%d) from identity %s", mConnId, mIdentity.toString().c_str());
// grab local reference and clear main reference to prevent future
// access to object
sp<MediaPlayerBase> p;
@@ -810,11 +821,12 @@
p.clear();
}
if (p == NULL) {
- p = MediaPlayerFactory::createPlayer(playerType, mListener, mPid);
+ p = MediaPlayerFactory::createPlayer(playerType, mListener,
+ VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(mIdentity.pid)));
}
if (p != NULL) {
- p->setUID(mUid);
+ p->setUID(VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(mIdentity.uid)));
}
return p;
@@ -922,8 +934,8 @@
mAudioDeviceUpdatedListener = new AudioDeviceUpdatedNotifier(p);
if (!p->hardwareOutput()) {
- mAudioOutput = new AudioOutput(mAudioSessionId, IPCThreadState::self()->getCallingUid(),
- mPid, mAudioAttributes, mAudioDeviceUpdatedListener, mOpPackageName);
+ mAudioOutput = new AudioOutput(mAudioSessionId, mIdentity,
+ mAudioAttributes, mAudioDeviceUpdatedListener);
static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
}
@@ -1772,9 +1784,8 @@
#undef LOG_TAG
#define LOG_TAG "AudioSink"
-MediaPlayerService::AudioOutput::AudioOutput(audio_session_t sessionId, uid_t uid, int pid,
- const audio_attributes_t* attr, const sp<AudioSystem::AudioDeviceCallback>& deviceCallback,
- const std::string& opPackageName)
+MediaPlayerService::AudioOutput::AudioOutput(audio_session_t sessionId, const Identity& identity,
+ const audio_attributes_t* attr, const sp<AudioSystem::AudioDeviceCallback>& deviceCallback)
: mCallback(NULL),
mCallbackCookie(NULL),
mCallbackData(NULL),
@@ -1786,8 +1797,7 @@
mMsecsPerFrame(0),
mFrameSize(0),
mSessionId(sessionId),
- mUid(uid),
- mPid(pid),
+ mIdentity(identity),
mSendLevel(0.0),
mAuxEffectId(0),
mFlags(AUDIO_OUTPUT_FLAG_NONE),
@@ -1795,8 +1805,7 @@
mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE),
mDeviceCallbackEnabled(false),
- mDeviceCallback(deviceCallback),
- mOpPackageName(opPackageName)
+ mDeviceCallback(deviceCallback)
{
ALOGV("AudioOutput(%d)", sessionId);
if (attr != NULL) {
@@ -1822,8 +1831,7 @@
//static
void MediaPlayerService::AudioOutput::setMinBufferCount()
{
- char value[PROPERTY_VALUE_MAX];
- if (property_get("ro.kernel.qemu", value, 0)) {
+ if (property_get_bool("ro.boot.qemu", false)) {
mIsOnEmulator = true;
mMinBufferCount = 12; // to prevent systematic buffer underrun for emulator
}
@@ -2185,13 +2193,11 @@
mSessionId,
AudioTrack::TRANSFER_CALLBACK,
offloadInfo,
- mUid,
- mPid,
+ mIdentity,
mAttributes,
doNotReconnect,
1.0f, // default value for maxRequiredSpeed
- mSelectedDeviceId,
- mOpPackageName);
+ mSelectedDeviceId);
} else {
// TODO: Due to buffer memory concerns, we use a max target playback speed
// based on mPlaybackRate at the time of open (instead of kMaxRequiredSpeed),
@@ -2214,13 +2220,11 @@
mSessionId,
AudioTrack::TRANSFER_DEFAULT,
NULL, // offload info
- mUid,
- mPid,
+ mIdentity,
mAttributes,
doNotReconnect,
targetSpeed,
- mSelectedDeviceId,
- mOpPackageName);
+ mSelectedDeviceId);
}
// Set caller name so it can be logged in destructor.
// MediaMetricsConstants.h: AMEDIAMETRICS_PROP_CALLERNAME_VALUE_MEDIA
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index aca4369..35a65d3 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -27,12 +27,13 @@
#include <utils/String8.h>
#include <utils/Vector.h>
+#include <media/AidlConversion.h>
#include <media/AudioResamplerPublic.h>
#include <media/AudioSystem.h>
#include <media/MediaPlayerInterface.h>
#include <media/Metadata.h>
#include <media/stagefright/foundation/ABase.h>
-
+#include <android/media/permission/Identity.h>
#include <system/audio.h>
@@ -79,11 +80,9 @@
public:
AudioOutput(
audio_session_t sessionId,
- uid_t uid,
- int pid,
+ const media::permission::Identity& identity,
const audio_attributes_t * attr,
- const sp<AudioSystem::AudioDeviceCallback>& deviceCallback,
- const std::string& opPackageName);
+ const sp<AudioSystem::AudioDeviceCallback>& deviceCallback);
virtual ~AudioOutput();
virtual bool ready() const { return mTrack != 0; }
@@ -170,8 +169,7 @@
float mMsecsPerFrame;
size_t mFrameSize;
audio_session_t mSessionId;
- uid_t mUid;
- int mPid;
+ media::permission::Identity mIdentity;
float mSendLevel;
int mAuxEffectId;
audio_output_flags_t mFlags;
@@ -181,7 +179,6 @@
bool mDeviceCallbackEnabled;
wp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
mutable Mutex mLock;
- const std::string mOpPackageName;
// static variables below not protected by mutex
static bool mIsOnEmulator;
@@ -234,13 +231,13 @@
static void instantiate();
// IMediaPlayerService interface
- virtual sp<IMediaRecorder> createMediaRecorder(const String16 &opPackageName);
+ virtual sp<IMediaRecorder> createMediaRecorder(const media::permission::Identity &identity);
void removeMediaRecorderClient(const wp<MediaRecorderClient>& client);
virtual sp<IMediaMetadataRetriever> createMetadataRetriever();
virtual sp<IMediaPlayer> create(const sp<IMediaPlayerClient>& client,
audio_session_t audioSessionId,
- const std::string opPackageName);
+ const media::permission::Identity& identity);
virtual sp<IMediaCodecList> getCodecList() const;
@@ -382,7 +379,9 @@
void notify(int msg, int ext1, int ext2, const Parcel *obj);
- pid_t pid() const { return mPid; }
+ pid_t pid() const {
+ return VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(mIdentity.pid));
+ }
virtual status_t dump(int fd, const Vector<String16>& args);
audio_session_t getAudioSessionId() { return mAudioSessionId; }
@@ -412,12 +411,10 @@
friend class MediaPlayerService;
Client( const sp<MediaPlayerService>& service,
- pid_t pid,
+ const media::permission::Identity& identity,
int32_t connId,
const sp<IMediaPlayerClient>& client,
- audio_session_t audioSessionId,
- uid_t uid,
- const std::string& opPackageName);
+ audio_session_t audioSessionId);
Client();
virtual ~Client();
@@ -461,20 +458,18 @@
sp<MediaPlayerService> mService;
sp<IMediaPlayerClient> mClient;
sp<AudioOutput> mAudioOutput;
- pid_t mPid;
+ const media::permission::Identity mIdentity;
status_t mStatus;
bool mLoop;
int32_t mConnId;
audio_session_t mAudioSessionId;
audio_attributes_t * mAudioAttributes;
- uid_t mUid;
sp<ANativeWindow> mConnectedWindow;
sp<IBinder> mConnectedWindowBinder;
struct sockaddr_in mRetransmitEndpoint;
bool mRetransmitEndpointValid;
sp<Client> mNextClient;
sp<MediaPlayerBase::Listener> mListener;
- const std::string mOpPackageName;
// Metadata filters.
media::Metadata::Filter mMetadataAllow; // protected by mLock
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index 1e72dd1..e2c8f8f 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -124,12 +124,10 @@
ALOGE("Invalid audio source: %d", as);
return BAD_VALUE;
}
- pid_t pid = IPCThreadState::self()->getCallingPid();
- uid_t uid = IPCThreadState::self()->getCallingUid();
if ((as == AUDIO_SOURCE_FM_TUNER
- && !(captureAudioOutputAllowed(pid, uid) || captureTunerAudioInputAllowed(pid, uid)))
- || !recordingAllowed(String16(""), pid, uid)) {
+ && !(captureAudioOutputAllowed(mIdentity) || captureTunerAudioInputAllowed(mIdentity)))
+ || !recordingAllowed(mIdentity)) {
return PERMISSION_DENIED;
}
Mutex::Autolock lock(mLock);
@@ -378,12 +376,13 @@
return NO_ERROR;
}
-MediaRecorderClient::MediaRecorderClient(const sp<MediaPlayerService>& service, pid_t pid,
- const String16& opPackageName)
+MediaRecorderClient::MediaRecorderClient(const sp<MediaPlayerService>& service,
+ const Identity& identity)
{
ALOGV("Client constructor");
- mPid = pid;
- mRecorder = new StagefrightRecorder(opPackageName);
+ // identity already validated in createMediaRecorder
+ mIdentity = identity;
+ mRecorder = new StagefrightRecorder(identity);
mMediaPlayerService = service;
}
diff --git a/media/libmediaplayerservice/MediaRecorderClient.h b/media/libmediaplayerservice/MediaRecorderClient.h
index e041855..24c6ee1 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.h
+++ b/media/libmediaplayerservice/MediaRecorderClient.h
@@ -22,6 +22,7 @@
#include <media/AudioSystem.h>
#include <media/IMediaRecorder.h>
+#include <android/media/permission/Identity.h>
#include <vector>
@@ -93,14 +94,13 @@
MediaRecorderClient(
const sp<MediaPlayerService>& service,
- pid_t pid,
- const String16& opPackageName);
+ const media::permission::Identity& identity);
virtual ~MediaRecorderClient();
std::vector<DeathNotifier> mDeathNotifiers;
sp<AudioDeviceUpdatedNotifier> mAudioDeviceUpdatedNotifier;
- pid_t mPid;
+ media::permission::Identity mIdentity;
mutable Mutex mLock;
MediaRecorderBase *mRecorder;
sp<MediaPlayerService> mMediaPlayerService;
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index ecbdf61..b485b1e 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -33,6 +33,7 @@
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
+#include <media/AidlConversion.h>
#include <media/IMediaPlayerService.h>
#include <media/MediaMetricsItem.h>
#include <media/stagefright/foundation/ABuffer.h>
@@ -114,8 +115,8 @@
}
-StagefrightRecorder::StagefrightRecorder(const String16 &opPackageName)
- : MediaRecorderBase(opPackageName),
+StagefrightRecorder::StagefrightRecorder(const Identity& clientIdentity)
+ : MediaRecorderBase(clientIdentity),
mWriter(NULL),
mOutputFd(-1),
mAudioSource((audio_source_t)AUDIO_SOURCE_CNT), // initialize with invalid value
@@ -157,7 +158,7 @@
// we run as part of the media player service; what we really want to
// know is the app which requested the recording.
- mMetricsItem->setUid(mClientUid);
+ mMetricsItem->setUid(VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(mClient.uid)));
// populate the values from the raw fields.
@@ -1129,7 +1130,8 @@
}
status_t StagefrightRecorder::setClientName(const String16& clientName) {
- mClientName = clientName;
+
+ mClient.packageName = VALUE_OR_RETURN_STATUS(legacy2aidl_String16_string(clientName));
return OK;
}
@@ -1141,10 +1143,6 @@
return INVALID_OPERATION;
}
- // Get UID and PID here for permission checking
- mClientUid = IPCThreadState::self()->getCallingUid();
- mClientPid = IPCThreadState::self()->getCallingPid();
-
status_t status = OK;
switch (mOutputFormat) {
@@ -1344,12 +1342,10 @@
sp<AudioSource> audioSource =
new AudioSource(
&attr,
- mOpPackageName,
+ mClient,
sourceSampleRate,
mAudioChannels,
mSampleRate,
- mClientUid,
- mClientPid,
mSelectedDeviceId,
mSelectedMicDirection,
mSelectedMicFieldDimension);
@@ -1871,6 +1867,10 @@
Size videoSize;
videoSize.width = mVideoWidth;
videoSize.height = mVideoHeight;
+ uid_t uid = VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_uid_t(mClient.uid));
+ pid_t pid = VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_pid_t(mClient.pid));
+ String16 clientName = VALUE_OR_RETURN_STATUS(
+ aidl2legacy_string_view_String16(mClient.packageName.value_or("")));
if (mCaptureFpsEnable) {
if (!(mCaptureFps > 0.)) {
ALOGE("Invalid mCaptureFps value: %lf", mCaptureFps);
@@ -1878,13 +1878,13 @@
}
mCameraSourceTimeLapse = CameraSourceTimeLapse::CreateFromCamera(
- mCamera, mCameraProxy, mCameraId, mClientName, mClientUid, mClientPid,
+ mCamera, mCameraProxy, mCameraId, clientName, uid, pid,
videoSize, mFrameRate, mPreviewSurface,
std::llround(1e6 / mCaptureFps));
*cameraSource = mCameraSourceTimeLapse;
} else {
*cameraSource = CameraSource::CreateFromCamera(
- mCamera, mCameraProxy, mCameraId, mClientName, mClientUid, mClientPid,
+ mCamera, mCameraProxy, mCameraId, clientName, uid, pid,
videoSize, mFrameRate,
mPreviewSurface);
}
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index 4bba869..278f348 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -26,6 +26,9 @@
#include <system/audio.h>
#include <media/hardware/MetadataBufferType.h>
+#include <android/media/permission/Identity.h>
+
+using namespace android::media::permission;
namespace android {
@@ -42,7 +45,7 @@
struct ALooper;
struct StagefrightRecorder : public MediaRecorderBase {
- explicit StagefrightRecorder(const String16 &opPackageName);
+ explicit StagefrightRecorder(const Identity& clientIdentity);
virtual ~StagefrightRecorder();
virtual status_t init();
virtual status_t setAudioSource(audio_source_t as);
@@ -98,9 +101,6 @@
sp<IGraphicBufferProducer> mPreviewSurface;
sp<PersistentSurface> mPersistentSurface;
sp<IMediaRecorderClient> mListener;
- String16 mClientName;
- uid_t mClientUid;
- pid_t mClientPid;
sp<MediaWriter> mWriter;
int mOutputFd;
sp<AudioSource> mAudioSourceNode;
diff --git a/media/libmediaplayerservice/tests/stagefrightRecorder/Android.bp b/media/libmediaplayerservice/tests/stagefrightRecorder/Android.bp
index b84d64b..5b16911 100644
--- a/media/libmediaplayerservice/tests/stagefrightRecorder/Android.bp
+++ b/media/libmediaplayerservice/tests/stagefrightRecorder/Android.bp
@@ -73,6 +73,8 @@
"libstagefright",
"libstagefright_foundation",
"libutils",
+ "media_permission-aidl-cpp",
+ "libaudioclient_aidl_conversion",
],
cflags: [
diff --git a/media/libmediaplayerservice/tests/stagefrightRecorder/StagefrightRecorderTest.cpp b/media/libmediaplayerservice/tests/stagefrightRecorder/StagefrightRecorderTest.cpp
index 5751631..6dea53d 100644
--- a/media/libmediaplayerservice/tests/stagefrightRecorder/StagefrightRecorderTest.cpp
+++ b/media/libmediaplayerservice/tests/stagefrightRecorder/StagefrightRecorderTest.cpp
@@ -59,7 +59,10 @@
}
void SetUp() override {
- mStfRecorder = new StagefrightRecorder(String16(LOG_TAG));
+ // TODO b/182392769: use identity util
+ Identity identity;
+ identity.packageName = std::string(LOG_TAG);
+ mStfRecorder = new StagefrightRecorder(identity);
ASSERT_NE(mStfRecorder, nullptr) << "Failed to create the instance of recorder";
mOutputAudioFp = fopen(OUTPUT_FILE_NAME_AUDIO, "wb");
diff --git a/media/libmediatranscoding/Android.bp b/media/libmediatranscoding/Android.bp
index 534fa91..042850c 100644
--- a/media/libmediatranscoding/Android.bp
+++ b/media/libmediatranscoding/Android.bp
@@ -82,6 +82,7 @@
srcs: [
"TranscoderWrapper.cpp",
"TranscodingClientManager.cpp",
+ "TranscodingLogger.cpp",
"TranscodingResourcePolicy.cpp",
"TranscodingSessionController.cpp",
"TranscodingThermalPolicy.cpp",
@@ -96,6 +97,7 @@
"libutils",
"libmediatranscoder",
"libmediandk",
+ "libstatssocket#30",
],
export_shared_lib_headers: [
"libmediandk",
@@ -106,6 +108,7 @@
static_libs: [
"mediatranscoding_aidl_interface-ndk_platform",
"resourceobserver_aidl_interface-V1-ndk_platform",
+ "libstatslog_media",
],
cflags: [
@@ -126,3 +129,43 @@
cfi: true,
},
}
+
+cc_library_static {
+ name: "libstatslog_media",
+ generated_sources: ["statslog_media.cpp"],
+ generated_headers: ["statslog_media.h"],
+ min_sdk_version: "29",
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ export_generated_headers: ["statslog_media.h"],
+ apex_available: [
+ "com.android.media",
+ "test_com.android.media",
+ ],
+ shared_libs: [
+ "libcutils",
+ "liblog",
+ "libstatssocket#30",
+ "libutils",
+ ],
+}
+
+genrule {
+ name: "statslog_media.h",
+ tools: ["stats-log-api-gen"],
+ cmd: "$(location stats-log-api-gen) --header $(genDir)/statslog_media.h --module media --namespace android,media,stats",
+ out: [
+ "statslog_media.h",
+ ],
+}
+
+genrule {
+ name: "statslog_media.cpp",
+ tools: ["stats-log-api-gen"],
+ cmd: "$(location stats-log-api-gen) --cpp $(genDir)/statslog_media.cpp --module media --namespace android,media,stats --importHeader statslog_media.h",
+ out: [
+ "statslog_media.cpp",
+ ],
+}
\ No newline at end of file
diff --git a/media/libmediatranscoding/TranscoderWrapper.cpp b/media/libmediatranscoding/TranscoderWrapper.cpp
index 4bd4105..d9c98c6 100644
--- a/media/libmediatranscoding/TranscoderWrapper.cpp
+++ b/media/libmediatranscoding/TranscoderWrapper.cpp
@@ -56,34 +56,34 @@
}
}
-static AMediaFormat* getVideoFormat(
+static std::shared_ptr<AMediaFormat> getVideoFormat(
const char* originalMime,
const std::optional<TranscodingVideoTrackFormat>& requestedFormat) {
if (requestedFormat == std::nullopt) {
return nullptr;
}
- AMediaFormat* format = AMediaFormat_new();
+ std::shared_ptr<AMediaFormat> format =
+ std::shared_ptr<AMediaFormat>(AMediaFormat_new(), &AMediaFormat_delete);
bool changed = false;
if (requestedFormat->codecType == TranscodingVideoCodecType::kHevc &&
strcmp(originalMime, AMEDIA_MIMETYPE_VIDEO_HEVC)) {
- AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, AMEDIA_MIMETYPE_VIDEO_HEVC);
+ AMediaFormat_setString(format.get(), AMEDIAFORMAT_KEY_MIME, AMEDIA_MIMETYPE_VIDEO_HEVC);
changed = true;
} else if (requestedFormat->codecType == TranscodingVideoCodecType::kAvc &&
strcmp(originalMime, AMEDIA_MIMETYPE_VIDEO_AVC)) {
- AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, AMEDIA_MIMETYPE_VIDEO_AVC);
+ AMediaFormat_setString(format.get(), AMEDIAFORMAT_KEY_MIME, AMEDIA_MIMETYPE_VIDEO_AVC);
changed = true;
}
if (requestedFormat->bitrateBps > 0) {
- AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, requestedFormat->bitrateBps);
+ AMediaFormat_setInt32(format.get(), AMEDIAFORMAT_KEY_BIT_RATE, requestedFormat->bitrateBps);
changed = true;
}
// TODO: translate other fields from requestedFormat to the format for MediaTranscoder.
// Also need to determine more settings to expose in TranscodingVideoTrackFormat.
if (!changed) {
- AMediaFormat_delete(format);
// Use null format for passthru.
- format = nullptr;
+ format.reset();
}
return format;
}
@@ -180,8 +180,10 @@
};
TranscoderWrapper::TranscoderWrapper(const std::shared_ptr<TranscoderCallbackInterface>& cb,
+ const std::shared_ptr<TranscodingLogger>& logger,
int64_t heartBeatIntervalUs)
: mCallback(cb),
+ mLogger(logger),
mHeartBeatIntervalUs(heartBeatIntervalUs),
mCurrentClientId(0),
mCurrentSessionId(-1),
@@ -219,10 +221,10 @@
}
void TranscoderWrapper::start(ClientIdType clientId, SessionIdType sessionId,
- const TranscodingRequestParcel& request,
+ const TranscodingRequestParcel& request, uid_t callingUid,
const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
queueEvent(Event::Start, clientId, sessionId, [=, &request] {
- media_status_t err = handleStart(clientId, sessionId, request, clientCb);
+ media_status_t err = handleStart(clientId, sessionId, request, callingUid, clientCb);
if (err != AMEDIA_OK) {
cleanup();
reportError(clientId, sessionId, err);
@@ -253,10 +255,10 @@
}
void TranscoderWrapper::resume(ClientIdType clientId, SessionIdType sessionId,
- const TranscodingRequestParcel& request,
+ const TranscodingRequestParcel& request, uid_t callingUid,
const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
queueEvent(Event::Resume, clientId, sessionId, [=, &request] {
- media_status_t err = handleResume(clientId, sessionId, request, clientCb);
+ media_status_t err = handleResume(clientId, sessionId, request, callingUid, clientCb);
if (err != AMEDIA_OK) {
cleanup();
reportError(clientId, sessionId, err);
@@ -280,6 +282,7 @@
} else {
ALOGI("transcoder stopped");
}
+ logSessionEnded(TranscodingLogger::SessionEndedReason::CANCELLED, err);
cleanup();
} else {
// For sessions that's not currently running, release any pausedState for the session.
@@ -297,6 +300,7 @@
queueEvent(Event::Finish, clientId, sessionId, [=] {
if (mTranscoder != nullptr && clientId == mCurrentClientId &&
sessionId == mCurrentSessionId) {
+ logSessionEnded(TranscodingLogger::SessionEndedReason::FINISHED, AMEDIA_OK);
cleanup();
}
@@ -314,6 +318,7 @@
[=] {
if (mTranscoder != nullptr && clientId == mCurrentClientId &&
sessionId == mCurrentSessionId) {
+ logSessionEnded(TranscodingLogger::SessionEndedReason::ERROR, error);
cleanup();
}
reportError(clientId, sessionId, error);
@@ -345,7 +350,8 @@
media_status_t TranscoderWrapper::setupTranscoder(
ClientIdType clientId, SessionIdType sessionId, const TranscodingRequestParcel& request,
- const std::shared_ptr<ITranscodingClientCallback>& clientCb,
+ uid_t callingUid, const std::shared_ptr<ITranscodingClientCallback>& clientCb,
+ TranscodingLogger::SessionEndedReason* failureReason,
const std::shared_ptr<ndk::ScopedAParcel>& pausedState) {
if (clientCb == nullptr) {
ALOGE("client callback is null");
@@ -364,6 +370,7 @@
status = clientCb->openFileDescriptor(request.sourceFilePath, "r", &srcFd);
if (!status.isOk() || srcFd.get() < 0) {
ALOGE("failed to open source");
+ *failureReason = TranscodingLogger::SessionEndedReason::OPEN_SRC_FD_FAILED;
return AMEDIA_ERROR_IO;
}
srcFdInt = srcFd.get();
@@ -377,6 +384,7 @@
status = clientCb->openFileDescriptor(request.destinationFilePath, "rw", &dstFd);
if (!status.isOk() || dstFd.get() < 0) {
ALOGE("failed to open destination");
+ *failureReason = TranscodingLogger::SessionEndedReason::OPEN_DST_FD_FAILED;
return AMEDIA_ERROR_IO;
}
dstFdInt = dstFd.get();
@@ -384,41 +392,46 @@
mCurrentClientId = clientId;
mCurrentSessionId = sessionId;
+ mCurrentCallingUid = callingUid;
mTranscoderCb = std::make_shared<CallbackImpl>(shared_from_this(), clientId, sessionId);
mTranscoder = MediaTranscoder::create(mTranscoderCb, mHeartBeatIntervalUs, request.clientPid,
request.clientUid, pausedState);
if (mTranscoder == nullptr) {
ALOGE("failed to create transcoder");
+ *failureReason = TranscodingLogger::SessionEndedReason::CREATE_FAILED;
return AMEDIA_ERROR_UNKNOWN;
}
media_status_t err = mTranscoder->configureSource(srcFdInt);
if (err != AMEDIA_OK) {
ALOGE("failed to configure source: %d", err);
+ *failureReason = TranscodingLogger::SessionEndedReason::CONFIG_SRC_FAILED;
return err;
}
std::vector<std::shared_ptr<AMediaFormat>> trackFormats = mTranscoder->getTrackFormats();
if (trackFormats.size() == 0) {
ALOGE("failed to get track formats!");
+ *failureReason = TranscodingLogger::SessionEndedReason::NO_TRACKS;
return AMEDIA_ERROR_MALFORMED;
}
for (int i = 0; i < trackFormats.size(); ++i) {
- AMediaFormat* format = nullptr;
+ std::shared_ptr<AMediaFormat> format;
const char* mime = nullptr;
AMediaFormat_getString(trackFormats[i].get(), AMEDIAFORMAT_KEY_MIME, &mime);
if (!strncmp(mime, "video/", 6)) {
format = getVideoFormat(mime, request.requestedVideoTrackFormat);
+
+ mSrcFormat = trackFormats[i];
+ mDstFormat = format;
}
- err = mTranscoder->configureTrackFormat(i, format);
- if (format != nullptr) {
- AMediaFormat_delete(format);
- }
+ err = mTranscoder->configureTrackFormat(i, format.get());
if (err != AMEDIA_OK) {
ALOGE("failed to configure track format for track %d: %d", i, err);
+ *failureReason = TranscodingLogger::SessionEndedReason::CONFIG_TRACK_FAILED;
return err;
}
}
@@ -426,6 +439,7 @@
err = mTranscoder->configureDestination(dstFdInt);
if (err != AMEDIA_OK) {
ALOGE("failed to configure dest: %d", err);
+ *failureReason = TranscodingLogger::SessionEndedReason::CONFIG_DST_FAILED;
return err;
}
@@ -434,17 +448,23 @@
media_status_t TranscoderWrapper::handleStart(
ClientIdType clientId, SessionIdType sessionId, const TranscodingRequestParcel& request,
- const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
+ uid_t callingUid, const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
ALOGI("%s: setting up transcoder for start", __FUNCTION__);
- media_status_t err = setupTranscoder(clientId, sessionId, request, clientCb);
+ TranscodingLogger::SessionEndedReason reason = TranscodingLogger::SessionEndedReason::UNKNOWN;
+ media_status_t err =
+ setupTranscoder(clientId, sessionId, request, callingUid, clientCb, &reason);
if (err != AMEDIA_OK) {
ALOGI("%s: failed to setup transcoder", __FUNCTION__);
+ logSessionEnded(reason, err);
return err;
}
+ mTranscodeStartTime = std::chrono::steady_clock::now();
+
err = mTranscoder->start();
if (err != AMEDIA_OK) {
ALOGE("%s: failed to start transcoder: %d", __FUNCTION__, err);
+ logSessionEnded(TranscodingLogger::SessionEndedReason::START_FAILED, err);
return err;
}
@@ -467,6 +487,7 @@
std::shared_ptr<ndk::ScopedAParcel> pauseStates;
media_status_t err = mTranscoder->pause(&pauseStates);
+ logSessionEnded(TranscodingLogger::SessionEndedReason::PAUSED, err);
if (err != AMEDIA_OK) {
ALOGE("%s: failed to pause transcoder: %d", __FUNCTION__, err);
return err;
@@ -479,7 +500,7 @@
media_status_t TranscoderWrapper::handleResume(
ClientIdType clientId, SessionIdType sessionId, const TranscodingRequestParcel& request,
- const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
+ uid_t callingUid, const std::shared_ptr<ITranscodingClientCallback>& clientCb) {
std::shared_ptr<ndk::ScopedAParcel> pausedState;
auto it = mPausedStateMap.find(SessionKeyType(clientId, sessionId));
if (it != mPausedStateMap.end()) {
@@ -491,15 +512,23 @@
}
ALOGI("%s: setting up transcoder for resume", __FUNCTION__);
- media_status_t err = setupTranscoder(clientId, sessionId, request, clientCb, pausedState);
+ TranscodingLogger::SessionEndedReason reason = TranscodingLogger::SessionEndedReason::UNKNOWN;
+ media_status_t err = setupTranscoder(clientId, sessionId, request, callingUid, clientCb,
+ &reason, pausedState);
if (err != AMEDIA_OK) {
ALOGE("%s: failed to setup transcoder: %d", __FUNCTION__, err);
+ logSessionEnded(reason, err);
return err;
}
+ // Note: For now resume() will just restart transcoding from the beginning, so there is no need
+ // to distinguish between resume and start from a performance perspective.
+ mTranscodeStartTime = std::chrono::steady_clock::now();
+
err = mTranscoder->resume();
if (err != AMEDIA_OK) {
ALOGE("%s: failed to resume transcoder: %d", __FUNCTION__, err);
+ logSessionEnded(TranscodingLogger::SessionEndedReason::RESUME_FAILED, err);
return err;
}
@@ -510,8 +539,23 @@
void TranscoderWrapper::cleanup() {
mCurrentClientId = 0;
mCurrentSessionId = -1;
+ mCurrentCallingUid = -1;
mTranscoderCb = nullptr;
mTranscoder = nullptr;
+ mSrcFormat = nullptr;
+ mDstFormat = nullptr;
+}
+
+void TranscoderWrapper::logSessionEnded(const TranscodingLogger::SessionEndedReason& reason,
+ int error) {
+ std::chrono::microseconds transcodeDuration(-1);
+ if (reason == TranscodingLogger::SessionEndedReason::FINISHED && error == AMEDIA_OK) {
+ transcodeDuration = std::chrono::duration_cast<std::chrono::microseconds>(
+ std::chrono::steady_clock::now() - mTranscodeStartTime);
+ }
+
+ mLogger->logSessionEnded(reason, mCurrentCallingUid, error, transcodeDuration, mSrcFormat.get(),
+ mDstFormat.get());
}
void TranscoderWrapper::queueEvent(Event::Type type, ClientIdType clientId, SessionIdType sessionId,
@@ -555,5 +599,4 @@
lock.lock();
}
}
-
} // namespace android
diff --git a/media/libmediatranscoding/TranscodingClientManager.cpp b/media/libmediatranscoding/TranscodingClientManager.cpp
index 76bb33e..06c5421 100644
--- a/media/libmediatranscoding/TranscodingClientManager.cpp
+++ b/media/libmediatranscoding/TranscodingClientManager.cpp
@@ -162,8 +162,8 @@
int32_t sessionId = mNextSessionId.fetch_add(1);
- *_aidl_return = owner->mSessionController->submit(mClientId, sessionId, in_clientUid,
- in_request, mClientCallback);
+ *_aidl_return = owner->mSessionController->submit(mClientId, sessionId, callingUid,
+ in_clientUid, in_request, mClientCallback);
if (*_aidl_return) {
out_session->sessionId = sessionId;
diff --git a/media/libmediatranscoding/TranscodingLogger.cpp b/media/libmediatranscoding/TranscodingLogger.cpp
new file mode 100644
index 0000000..29a52b0
--- /dev/null
+++ b/media/libmediatranscoding/TranscodingLogger.cpp
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// #define LOG_NDEBUG 0
+#define LOG_TAG "TranscodingLogger"
+
+#include <media/NdkCommon.h>
+#include <media/TranscodingLogger.h>
+#include <statslog_media.h>
+#include <utils/Log.h>
+
+#include <cmath>
+#include <string>
+
+namespace android {
+
+static_assert(TranscodingLogger::UNKNOWN ==
+ android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__UNKNOWN,
+ "Session event mismatch");
+static_assert(TranscodingLogger::FINISHED ==
+ android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__FINISHED,
+ "Session event mismatch");
+static_assert(TranscodingLogger::ERROR ==
+ android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__ERROR,
+ "Session event mismatch");
+static_assert(TranscodingLogger::PAUSED ==
+ android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__PAUSED,
+ "Session event mismatch");
+static_assert(TranscodingLogger::CANCELLED ==
+ android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__CANCELLED,
+ "Session event mismatch");
+static_assert(TranscodingLogger::START_FAILED ==
+ android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__START_FAILED,
+ "Session event mismatch");
+static_assert(TranscodingLogger::RESUME_FAILED ==
+ android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__RESUME_FAILED,
+ "Session event mismatch");
+static_assert(TranscodingLogger::CREATE_FAILED ==
+ android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__CREATE_FAILED,
+ "Session event mismatch");
+static_assert(
+ TranscodingLogger::CONFIG_SRC_FAILED ==
+ android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__CONFIG_SRC_FAILED,
+ "Session event mismatch");
+static_assert(
+ TranscodingLogger::CONFIG_DST_FAILED ==
+ android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__CONFIG_DST_FAILED,
+ "Session event mismatch");
+static_assert(
+ TranscodingLogger::CONFIG_TRACK_FAILED ==
+ android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__CONFIG_TRACK_FAILED,
+ "Session event mismatch");
+static_assert(
+ TranscodingLogger::OPEN_SRC_FD_FAILED ==
+ android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__OPEN_SRC_FD_FAILED,
+ "Session event mismatch");
+static_assert(
+ TranscodingLogger::OPEN_DST_FD_FAILED ==
+ android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__OPEN_DST_FD_FAILED,
+ "Session event mismatch");
+static_assert(TranscodingLogger::NO_TRACKS ==
+ android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED__REASON__NO_TRACKS,
+ "Session event mismatch");
+
+static inline int32_t getInt32(AMediaFormat* fmt, const char* key, int32_t defaultValue = -1) {
+ int32_t value;
+ if (fmt == nullptr || !AMediaFormat_getInt32(fmt, key, &value)) {
+ ALOGW("Unable to get %s", key);
+ value = defaultValue;
+ }
+ return value;
+}
+
+// Note: returned string is owned by format and only valid until the next getString.
+static inline const char* getString(AMediaFormat* fmt, const char* key,
+ const char* defaultValue = "(null)") {
+ const char* value;
+ if (fmt == nullptr || !AMediaFormat_getString(fmt, key, &value)) {
+ ALOGW("Unable to get %s", key);
+ value = defaultValue;
+ }
+ return value;
+}
+
+TranscodingLogger::TranscodingLogger()
+ : mSessionEndedAtomWriter(&android::media::stats::stats_write) {}
+
+void TranscodingLogger::logSessionEnded(enum SessionEndedReason reason, uid_t callingUid,
+ int status, std::chrono::microseconds duration,
+ AMediaFormat* srcFormat, AMediaFormat* dstFormat) {
+ logSessionEnded(std::chrono::steady_clock::now(), reason, callingUid, status, duration,
+ srcFormat, dstFormat);
+}
+
+void TranscodingLogger::logSessionEnded(const std::chrono::steady_clock::time_point& now,
+ enum SessionEndedReason reason, uid_t callingUid,
+ int status, std::chrono::microseconds duration,
+ AMediaFormat* srcFormat, AMediaFormat* dstFormat) {
+ if (srcFormat == nullptr) {
+ ALOGE("Source format is null. Dropping event.");
+ return;
+ }
+
+ if (!shouldLogAtom(now, status)) {
+ ALOGD("Maximum logged event count reached. Dropping event.");
+ return;
+ }
+
+ // Extract the pieces of information to log.
+ const int32_t srcWidth = getInt32(srcFormat, AMEDIAFORMAT_KEY_WIDTH);
+ const int32_t srcHeight = getInt32(srcFormat, AMEDIAFORMAT_KEY_HEIGHT);
+ const char* srcMime = getString(srcFormat, AMEDIAFORMAT_KEY_MIME);
+ const int32_t srcProfile = getInt32(srcFormat, AMEDIAFORMAT_KEY_PROFILE);
+ const int32_t srcLevel = getInt32(srcFormat, AMEDIAFORMAT_KEY_LEVEL);
+ const int32_t srcFrameRate = getInt32(srcFormat, AMEDIAFORMAT_KEY_FRAME_RATE);
+ const int32_t srcFrameCount = getInt32(srcFormat, AMEDIAFORMAT_KEY_FRAME_COUNT);
+ const bool srcIsHdr = AMediaFormatUtils::VideoIsHdr(srcFormat);
+
+ int32_t dstWidth = getInt32(dstFormat, AMEDIAFORMAT_KEY_WIDTH, srcWidth);
+ int32_t dstHeight = getInt32(dstFormat, AMEDIAFORMAT_KEY_HEIGHT, srcHeight);
+ const char* dstMime = dstFormat == nullptr
+ ? "passthrough"
+ : getString(dstFormat, AMEDIAFORMAT_KEY_MIME, srcMime);
+ const bool dstIsHdr = false; // Transcoder always request SDR output.
+
+ int64_t tmpDurationUs;
+ const int32_t srcDurationMs =
+ AMediaFormat_getInt64(srcFormat, AMEDIAFORMAT_KEY_DURATION, &tmpDurationUs)
+ ? static_cast<int32_t>(tmpDurationUs / 1000)
+ : -1;
+
+ int32_t transcodeFrameRate = -1;
+ if (status == 0 && srcFrameCount > 0 && duration.count() > 0) {
+ std::chrono::duration<double> seconds{duration};
+ transcodeFrameRate = static_cast<int32_t>(
+ std::round(static_cast<double>(srcFrameCount) / seconds.count()));
+ }
+
+ // Write the atom.
+ mSessionEndedAtomWriter(android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED,
+ static_cast<int>(reason), callingUid, status, transcodeFrameRate,
+ srcWidth, srcHeight, srcMime, srcProfile, srcLevel, srcFrameRate,
+ srcDurationMs, srcIsHdr, dstWidth, dstHeight, dstMime, dstIsHdr);
+}
+
+bool TranscodingLogger::shouldLogAtom(const std::chrono::steady_clock::time_point& now,
+ int status) {
+ std::scoped_lock lock{mLock};
+ static const std::chrono::hours oneDay(24);
+
+ // Remove events older than one day.
+ while (mLastLoggedAtoms.size() > 0 && (now - mLastLoggedAtoms.front().first) >= oneDay) {
+ if (mLastLoggedAtoms.front().second == AMEDIA_OK) {
+ --mSuccessfulCount;
+ }
+ mLastLoggedAtoms.pop();
+ }
+
+ // Don't log if maximum number of events is reached.
+ if (mLastLoggedAtoms.size() >= kMaxAtomsPerDay) {
+ return false;
+ }
+
+ // Don't log if the event is successful and the maximum number of successful events is reached.
+ if (status == AMEDIA_OK && mSuccessfulCount >= kMaxSuccessfulAtomsPerDay) {
+ return false;
+ }
+
+ // Record the event.
+ if (status == AMEDIA_OK) {
+ ++mSuccessfulCount;
+ }
+ mLastLoggedAtoms.emplace(now, status);
+ return true;
+}
+
+void TranscodingLogger::setSessionEndedAtomWriter(const SessionEndedAtomWriter& writer) {
+ mSessionEndedAtomWriter = writer;
+}
+
+} // namespace android
diff --git a/media/libmediatranscoding/TranscodingSessionController.cpp b/media/libmediatranscoding/TranscodingSessionController.cpp
index d12af21..aeabe0f 100644
--- a/media/libmediatranscoding/TranscodingSessionController.cpp
+++ b/media/libmediatranscoding/TranscodingSessionController.cpp
@@ -87,15 +87,12 @@
// Whether watchdog is aborted and the monitoring thread should exit.
bool mAbort GUARDED_BY(mLock);
// When watchdog is active, the next timeout time point.
- std::chrono::system_clock::time_point mNextTimeoutTime GUARDED_BY(mLock);
+ std::chrono::steady_clock::time_point mNextTimeoutTime GUARDED_BY(mLock);
// When watchdog is active, the session being watched.
SessionKeyType mSessionToWatch GUARDED_BY(mLock);
std::thread mThread;
};
-static constexpr int64_t kWatchdogTimeoutUs = 3000000LL;
-static constexpr int64_t kTranscoderHeartBeatIntervalUs = 1000000LL;
-
TranscodingSessionController::Watchdog::Watchdog(TranscodingSessionController* owner,
int64_t timeoutUs)
: mOwner(owner),
@@ -159,7 +156,7 @@
// updateTimer_l() is only called with lock held.
void TranscodingSessionController::Watchdog::updateTimer_l() NO_THREAD_SAFETY_ANALYSIS {
std::chrono::microseconds timeout(mTimeoutUs);
- mNextTimeoutTime = std::chrono::system_clock::now() + timeout;
+ mNextTimeoutTime = std::chrono::steady_clock::now() + timeout;
}
// Unfortunately std::unique_lock is incompatible with -Wthread-safety.
@@ -188,12 +185,84 @@
}
}
///////////////////////////////////////////////////////////////////////////////
+struct TranscodingSessionController::Pacer {
+ Pacer(const ControllerConfig& config)
+ : mBurstThresholdMs(config.pacerBurstThresholdMs),
+ mBurstCountQuota(config.pacerBurstCountQuota),
+ mBurstTimeQuotaSec(config.pacerBurstTimeQuotaSeconds) {}
+
+ ~Pacer() = default;
+
+ void onSessionCompleted(uid_t uid, std::chrono::microseconds runningTime);
+ bool onSessionStarted(uid_t uid);
+
+private:
+ // Threshold of time between finish/start below which a back-to-back start is counted.
+ int32_t mBurstThresholdMs;
+ // Maximum allowed back-to-back start count.
+ int32_t mBurstCountQuota;
+ // Maximum allowed back-to-back running time.
+ int32_t mBurstTimeQuotaSec;
+
+ struct UidHistoryEntry {
+ std::chrono::steady_clock::time_point lastCompletedTime;
+ int32_t burstCount = 0;
+ std::chrono::steady_clock::duration burstDuration{0};
+ };
+ std::map<uid_t, UidHistoryEntry> mUidHistoryMap;
+};
+
+void TranscodingSessionController::Pacer::onSessionCompleted(
+ uid_t uid, std::chrono::microseconds runningTime) {
+ if (mUidHistoryMap.find(uid) == mUidHistoryMap.end()) {
+ mUidHistoryMap.emplace(uid, UidHistoryEntry{});
+ }
+ mUidHistoryMap[uid].lastCompletedTime = std::chrono::steady_clock::now();
+ mUidHistoryMap[uid].burstCount++;
+ mUidHistoryMap[uid].burstDuration += runningTime;
+}
+
+bool TranscodingSessionController::Pacer::onSessionStarted(uid_t uid) {
+ // If uid doesn't exist, this uid has no completed sessions. Skip.
+ if (mUidHistoryMap.find(uid) == mUidHistoryMap.end()) {
+ return true;
+ }
+
+ // TODO: if Thermal throttling or resoure lost happened to occurr between this start
+ // and the previous completion, we should deduct the paused time from the elapsed time.
+ // (Individual session's pause time, on the other hand, doesn't need to be deducted
+ // because it doesn't affect the gap between last completion and the start.
+ auto timeSinceLastComplete =
+ std::chrono::steady_clock::now() - mUidHistoryMap[uid].lastCompletedTime;
+ if (mUidHistoryMap[uid].burstCount >= mBurstCountQuota &&
+ mUidHistoryMap[uid].burstDuration >= std::chrono::seconds(mBurstTimeQuotaSec)) {
+ ALOGW("Pacer: uid %d: over quota, burst count %d, time %lldms", uid,
+ mUidHistoryMap[uid].burstCount, (long long)mUidHistoryMap[uid].burstDuration.count());
+ return false;
+ }
+
+ // If not over quota, allow the session, and reset as long as this is not too close
+ // to previous completion.
+ if (timeSinceLastComplete > std::chrono::milliseconds(mBurstThresholdMs)) {
+ ALOGV("Pacer: uid %d: reset quota", uid);
+ mUidHistoryMap[uid].burstCount = 0;
+ mUidHistoryMap[uid].burstDuration = std::chrono::milliseconds(0);
+ } else {
+ ALOGV("Pacer: uid %d: burst count %d, time %lldms", uid, mUidHistoryMap[uid].burstCount,
+ (long long)mUidHistoryMap[uid].burstDuration.count());
+ }
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
TranscodingSessionController::TranscodingSessionController(
const TranscoderFactoryType& transcoderFactory,
const std::shared_ptr<UidPolicyInterface>& uidPolicy,
const std::shared_ptr<ResourcePolicyInterface>& resourcePolicy,
- const std::shared_ptr<ThermalPolicyInterface>& thermalPolicy)
+ const std::shared_ptr<ThermalPolicyInterface>& thermalPolicy,
+ const ControllerConfig* config)
: mTranscoderFactory(transcoderFactory),
mUidPolicy(uidPolicy),
mResourcePolicy(resourcePolicy),
@@ -206,6 +275,13 @@
mSessionQueues.emplace(OFFLINE_UID, SessionQueueType());
mUidPackageNames[OFFLINE_UID] = "(offline)";
mThermalThrottling = thermalPolicy->getThrottlingStatus();
+ if (config != nullptr) {
+ mConfig = *config;
+ }
+ mPacer.reset(new Pacer(mConfig));
+ ALOGD("@@@ watchdog %lld, burst count %d, burst time %d, burst threshold %d",
+ (long long)mConfig.watchdogTimeoutUs, mConfig.pacerBurstCountQuota,
+ mConfig.pacerBurstTimeQuotaSeconds, mConfig.pacerBurstThresholdMs);
}
TranscodingSessionController::~TranscodingSessionController() {}
@@ -280,10 +356,21 @@
write(fd, result.string(), result.size());
}
+/*
+ * Returns nullptr if there is no session, or we're paused globally (due to resource lost,
+ * thermal throttling, etc.). Otherwise, return the session that should be run next.
+ */
TranscodingSessionController::Session* TranscodingSessionController::getTopSession_l() {
if (mSessionMap.empty()) {
return nullptr;
}
+
+ // Return nullptr if we're paused globally due to resource lost or thermal throttling.
+ if (((mResourcePolicy != nullptr && mResourceLost) ||
+ (mThermalPolicy != nullptr && mThermalThrottling))) {
+ return nullptr;
+ }
+
uid_t topUid = *mUidSortedList.begin();
SessionKeyType topSessionKey = *mSessionQueues[topUid].begin();
return &mSessionMap[topSessionKey];
@@ -313,9 +400,10 @@
if (state == newState) {
return;
}
- auto nowTime = std::chrono::system_clock::now();
+ auto nowTime = std::chrono::steady_clock::now();
if (state != INVALID) {
- std::chrono::microseconds elapsedTime = (nowTime - stateEnterTime);
+ std::chrono::microseconds elapsedTime =
+ std::chrono::duration_cast<std::chrono::microseconds>(nowTime - stateEnterTime);
switch (state) {
case PAUSED:
pausedTime = pausedTime + elapsedTime;
@@ -338,47 +426,60 @@
}
void TranscodingSessionController::updateCurrentSession_l() {
- Session* topSession = getTopSession_l();
Session* curSession = mCurrentSession;
- ALOGV("updateCurrentSession: topSession is %s, curSession is %s",
- topSession == nullptr ? "null" : sessionToString(topSession->key).c_str(),
- curSession == nullptr ? "null" : sessionToString(curSession->key).c_str());
+ Session* topSession = getTopSession_l();
- if (topSession == nullptr) {
- mCurrentSession = nullptr;
- return;
+ // Delayed init of transcoder and watchdog.
+ if (mTranscoder == nullptr) {
+ mTranscoder = mTranscoderFactory(shared_from_this());
+ mWatchdog = std::make_shared<Watchdog>(this, mConfig.watchdogTimeoutUs);
}
- bool shouldBeRunning = !((mResourcePolicy != nullptr && mResourceLost) ||
- (mThermalPolicy != nullptr && mThermalThrottling));
- // If we found a topSession that should be run, and it's not already running,
- // take some actions to ensure it's running.
- if (topSession != curSession ||
- (shouldBeRunning ^ (topSession->getState() == Session::RUNNING))) {
- if (mTranscoder == nullptr) {
- mTranscoder = mTranscoderFactory(shared_from_this(), kTranscoderHeartBeatIntervalUs);
- mWatchdog = std::make_shared<Watchdog>(this, kWatchdogTimeoutUs);
- }
+ // If we found a different top session, or the top session's running state is not
+ // correct. Take some actions to ensure it's correct.
+ while ((topSession = getTopSession_l()) != curSession ||
+ (topSession != nullptr && !topSession->isRunning())) {
+ ALOGV("updateCurrentSession_l: topSession is %s, curSession is %s",
+ topSession == nullptr ? "null" : sessionToString(topSession->key).c_str(),
+ curSession == nullptr ? "null" : sessionToString(curSession->key).c_str());
- // If current session is running, pause it first. Note this is true for either
- // cases: 1) If top session is changing, or 2) if top session is not changing but
- // the topSession's state is changing.
+ // If current session is running, pause it first. Note this is needed for either
+ // cases: 1) Top session is changing to another session, or 2) Top session is
+ // changing to null (which means we should be globally paused).
if (curSession != nullptr && curSession->getState() == Session::RUNNING) {
mTranscoder->pause(curSession->key.first, curSession->key.second);
setSessionState_l(curSession, Session::PAUSED);
}
- // If we are not experiencing resource loss nor thermal throttling, we can start
- // or resume the topSession now.
- if (shouldBeRunning) {
- if (topSession->getState() == Session::NOT_STARTED) {
- mTranscoder->start(topSession->key.first, topSession->key.second,
- topSession->request, topSession->callback.lock());
- } else if (topSession->getState() == Session::PAUSED) {
- mTranscoder->resume(topSession->key.first, topSession->key.second,
- topSession->request, topSession->callback.lock());
+
+ if (topSession == nullptr) {
+ // Nothing more to run (either no session or globally paused).
+ break;
+ }
+
+ // Otherwise, ensure topSession is running.
+ if (topSession->getState() == Session::NOT_STARTED) {
+ if (!mPacer->onSessionStarted(topSession->clientUid)) {
+ // Unfortunately this uid is out of quota for new sessions.
+ // Drop this sesion and try another one.
+ {
+ auto clientCallback = mSessionMap[topSession->key].callback.lock();
+ if (clientCallback != nullptr) {
+ clientCallback->onTranscodingFailed(
+ topSession->key.second, TranscodingErrorCode::kDroppedByService);
+ }
+ }
+ removeSession_l(topSession->key, Session::DROPPED_BY_PACER);
+ continue;
}
+ mTranscoder->start(topSession->key.first, topSession->key.second, topSession->request,
+ topSession->callingUid, topSession->callback.lock());
+ setSessionState_l(topSession, Session::RUNNING);
+ } else if (topSession->getState() == Session::PAUSED) {
+ mTranscoder->resume(topSession->key.first, topSession->key.second, topSession->request,
+ topSession->callingUid, topSession->callback.lock());
setSessionState_l(topSession, Session::RUNNING);
}
+ break;
}
mCurrentSession = topSession;
}
@@ -393,7 +494,7 @@
}
// Remove session from uid's queue.
- const uid_t uid = mSessionMap[sessionKey].uid;
+ const uid_t uid = mSessionMap[sessionKey].clientUid;
SessionQueueType& sessionQueue = mSessionQueues[uid];
auto it = std::find(sessionQueue.begin(), sessionQueue.end(), sessionKey);
if (it == sessionQueue.end()) {
@@ -419,6 +520,12 @@
}
setSessionState_l(&mSessionMap[sessionKey], finalState);
+
+ if (finalState == Session::FINISHED || finalState == Session::ERROR) {
+ mPacer->onSessionCompleted(mSessionMap[sessionKey].clientUid,
+ mSessionMap[sessionKey].runningTime);
+ }
+
mSessionHistory.push_back(mSessionMap[sessionKey]);
if (mSessionHistory.size() > kSessionHistoryMax) {
mSessionHistory.erase(mSessionHistory.begin());
@@ -482,13 +589,13 @@
}
bool TranscodingSessionController::submit(
- ClientIdType clientId, SessionIdType sessionId, uid_t uid,
+ ClientIdType clientId, SessionIdType sessionId, uid_t callingUid, uid_t clientUid,
const TranscodingRequestParcel& request,
const std::weak_ptr<ITranscodingClientCallback>& callback) {
SessionKeyType sessionKey = std::make_pair(clientId, sessionId);
ALOGV("%s: session %s, uid %d, prioirty %d", __FUNCTION__, sessionToString(sessionKey).c_str(),
- uid, (int32_t)request.priority);
+ clientUid, (int32_t)request.priority);
std::scoped_lock lock{mLock};
@@ -498,21 +605,20 @@
}
// Add the uid package name to the store of package names we already know.
- if (mUidPackageNames.count(uid) == 0) {
- mUidPackageNames.emplace(uid, request.clientPackageName);
+ if (mUidPackageNames.count(clientUid) == 0) {
+ mUidPackageNames.emplace(clientUid, request.clientPackageName);
}
// TODO(chz): only support offline vs real-time for now. All kUnspecified sessions
// go to offline queue.
if (request.priority == TranscodingSessionPriority::kUnspecified) {
- uid = OFFLINE_UID;
+ clientUid = OFFLINE_UID;
}
// Add session to session map.
mSessionMap[sessionKey].key = sessionKey;
- mSessionMap[sessionKey].uid = uid;
- mSessionMap[sessionKey].lastProgress = 0;
- mSessionMap[sessionKey].pauseCount = 0;
+ mSessionMap[sessionKey].clientUid = clientUid;
+ mSessionMap[sessionKey].callingUid = callingUid;
mSessionMap[sessionKey].request = request;
mSessionMap[sessionKey].callback = callback;
setSessionState_l(&mSessionMap[sessionKey], Session::NOT_STARTED);
@@ -520,25 +626,25 @@
// If it's an offline session, the queue was already added in constructor.
// If it's a real-time sessions, check if a queue is already present for the uid,
// and add a new queue if needed.
- if (uid != OFFLINE_UID) {
- if (mSessionQueues.count(uid) == 0) {
- mUidPolicy->registerMonitorUid(uid);
- if (mUidPolicy->isUidOnTop(uid)) {
- mUidSortedList.push_front(uid);
+ if (clientUid != OFFLINE_UID) {
+ if (mSessionQueues.count(clientUid) == 0) {
+ mUidPolicy->registerMonitorUid(clientUid);
+ if (mUidPolicy->isUidOnTop(clientUid)) {
+ mUidSortedList.push_front(clientUid);
} else {
// Shouldn't be submitting real-time requests from non-top app,
// put it in front of the offline queue.
- mUidSortedList.insert(mOfflineUidIterator, uid);
+ mUidSortedList.insert(mOfflineUidIterator, clientUid);
}
- } else if (uid != *mUidSortedList.begin()) {
- if (mUidPolicy->isUidOnTop(uid)) {
- mUidSortedList.remove(uid);
- mUidSortedList.push_front(uid);
+ } else if (clientUid != *mUidSortedList.begin()) {
+ if (mUidPolicy->isUidOnTop(clientUid)) {
+ mUidSortedList.remove(clientUid);
+ mUidSortedList.push_front(clientUid);
}
}
}
// Append this session to the uid's queue.
- mSessionQueues[uid].push_back(sessionKey);
+ mSessionQueues[clientUid].push_back(sessionKey);
updateCurrentSession_l();
@@ -557,7 +663,7 @@
if (sessionId < 0) {
for (auto it = mSessionMap.begin(); it != mSessionMap.end(); ++it) {
- if (it->first.first == clientId && it->second.uid != OFFLINE_UID) {
+ if (it->first.first == clientId && it->second.clientUid != OFFLINE_UID) {
sessionsToRemove.push_back(it->first);
}
}
@@ -687,7 +793,7 @@
mTranscoder->stop(clientId, sessionId, true /*abandon*/);
// Clear the last ref count before we create new transcoder.
mTranscoder = nullptr;
- mTranscoder = mTranscoderFactory(shared_from_this(), kTranscoderHeartBeatIntervalUs);
+ mTranscoder = mTranscoderFactory(shared_from_this());
}
{
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingErrorCode.aidl b/media/libmediatranscoding/aidl/android/media/TranscodingErrorCode.aidl
index 23072ff..5349fe1 100644
--- a/media/libmediatranscoding/aidl/android/media/TranscodingErrorCode.aidl
+++ b/media/libmediatranscoding/aidl/android/media/TranscodingErrorCode.aidl
@@ -23,13 +23,19 @@
*/
@Backing(type = "int")
enum TranscodingErrorCode {
+ // Errors exposed to client side.
kNoError = 0,
- kUnknown = 1,
- kMalformed = 2,
- kUnsupported = 3,
- kInvalidParameter = 4,
- kInvalidOperation = 5,
- kErrorIO = 6,
- kInsufficientResources = 7,
- kWatchdogTimeout = 8,
+ kDroppedByService = 1,
+ kServiceUnavailable = 2,
+
+ // Other private errors.
+ kPrivateErrorFirst = 1000,
+ kUnknown = kPrivateErrorFirst + 0,
+ kMalformed = kPrivateErrorFirst + 1,
+ kUnsupported = kPrivateErrorFirst + 2,
+ kInvalidParameter = kPrivateErrorFirst + 3,
+ kInvalidOperation = kPrivateErrorFirst + 4,
+ kErrorIO = kPrivateErrorFirst + 5,
+ kInsufficientResources = kPrivateErrorFirst + 6,
+ kWatchdogTimeout = kPrivateErrorFirst + 7,
}
\ No newline at end of file
diff --git a/media/libmediatranscoding/include/media/ControllerClientInterface.h b/media/libmediatranscoding/include/media/ControllerClientInterface.h
index 3fd4f0c..0d13607 100644
--- a/media/libmediatranscoding/include/media/ControllerClientInterface.h
+++ b/media/libmediatranscoding/include/media/ControllerClientInterface.h
@@ -36,8 +36,8 @@
* Returns true on success and false on failure. This call will fail is a session identified
* by <clientId, sessionId> already exists.
*/
- virtual bool submit(ClientIdType clientId, SessionIdType sessionId, uid_t uid,
- const TranscodingRequestParcel& request,
+ virtual bool submit(ClientIdType clientId, SessionIdType sessionId, uid_t callingUid,
+ uid_t clientUid, const TranscodingRequestParcel& request,
const std::weak_ptr<ITranscodingClientCallback>& clientCallback) = 0;
/**
diff --git a/media/libmediatranscoding/include/media/TranscoderInterface.h b/media/libmediatranscoding/include/media/TranscoderInterface.h
index 5f27d82..3b0bd3b 100644
--- a/media/libmediatranscoding/include/media/TranscoderInterface.h
+++ b/media/libmediatranscoding/include/media/TranscoderInterface.h
@@ -33,11 +33,11 @@
class TranscoderInterface {
public:
virtual void start(ClientIdType clientId, SessionIdType sessionId,
- const TranscodingRequestParcel& request,
+ const TranscodingRequestParcel& request, uid_t callingUid,
const std::shared_ptr<ITranscodingClientCallback>& clientCallback) = 0;
virtual void pause(ClientIdType clientId, SessionIdType sessionId) = 0;
virtual void resume(ClientIdType clientId, SessionIdType sessionId,
- const TranscodingRequestParcel& request,
+ const TranscodingRequestParcel& request, uid_t callingUid,
const std::shared_ptr<ITranscodingClientCallback>& clientCallback) = 0;
// Stop the specified session. If abandon is true, the transcoder wrapper will be discarded
// after the session stops.
diff --git a/media/libmediatranscoding/include/media/TranscoderWrapper.h b/media/libmediatranscoding/include/media/TranscoderWrapper.h
index 7935bbe..d3d4c86 100644
--- a/media/libmediatranscoding/include/media/TranscoderWrapper.h
+++ b/media/libmediatranscoding/include/media/TranscoderWrapper.h
@@ -18,8 +18,11 @@
#define ANDROID_TRANSCODER_WRAPPER_H
#include <media/NdkMediaError.h>
+#include <media/NdkMediaFormat.h>
#include <media/TranscoderInterface.h>
+#include <media/TranscodingLogger.h>
+#include <chrono>
#include <list>
#include <map>
#include <mutex>
@@ -37,16 +40,17 @@
public std::enable_shared_from_this<TranscoderWrapper> {
public:
TranscoderWrapper(const std::shared_ptr<TranscoderCallbackInterface>& cb,
+ const std::shared_ptr<TranscodingLogger>& logger,
int64_t heartBeatIntervalUs);
~TranscoderWrapper();
// TranscoderInterface
void start(ClientIdType clientId, SessionIdType sessionId,
- const TranscodingRequestParcel& request,
+ const TranscodingRequestParcel& request, uid_t callingUid,
const std::shared_ptr<ITranscodingClientCallback>& clientCallback) override;
void pause(ClientIdType clientId, SessionIdType sessionId) override;
void resume(ClientIdType clientId, SessionIdType sessionId,
- const TranscodingRequestParcel& request,
+ const TranscodingRequestParcel& request, uid_t callingUid,
const std::shared_ptr<ITranscodingClientCallback>& clientCallback) override;
void stop(ClientIdType clientId, SessionIdType sessionId, bool abandon = false) override;
// ~TranscoderInterface
@@ -76,6 +80,9 @@
std::shared_ptr<CallbackImpl> mTranscoderCb;
std::shared_ptr<MediaTranscoder> mTranscoder;
std::weak_ptr<TranscoderCallbackInterface> mCallback;
+ std::shared_ptr<TranscodingLogger> mLogger;
+ std::shared_ptr<AMediaFormat> mSrcFormat;
+ std::shared_ptr<AMediaFormat> mDstFormat;
int64_t mHeartBeatIntervalUs;
std::mutex mLock;
std::condition_variable mCondition;
@@ -83,6 +90,9 @@
std::map<SessionKeyType, std::shared_ptr<ndk::ScopedAParcel>> mPausedStateMap;
ClientIdType mCurrentClientId;
SessionIdType mCurrentSessionId;
+ uid_t mCurrentCallingUid;
+ std::chrono::steady_clock::time_point mTranscodeStartTime;
+
// Whether the looper has been created.
bool mLooperReady;
@@ -93,18 +103,20 @@
void onHeartBeat(ClientIdType clientId, SessionIdType sessionId);
media_status_t handleStart(ClientIdType clientId, SessionIdType sessionId,
- const TranscodingRequestParcel& request,
+ const TranscodingRequestParcel& request, uid_t callingUid,
const std::shared_ptr<ITranscodingClientCallback>& callback);
media_status_t handlePause(ClientIdType clientId, SessionIdType sessionId);
media_status_t handleResume(ClientIdType clientId, SessionIdType sessionId,
- const TranscodingRequestParcel& request,
+ const TranscodingRequestParcel& request, uid_t callingUid,
const std::shared_ptr<ITranscodingClientCallback>& callback);
media_status_t setupTranscoder(
ClientIdType clientId, SessionIdType sessionId, const TranscodingRequestParcel& request,
- const std::shared_ptr<ITranscodingClientCallback>& callback,
+ uid_t callingUid, const std::shared_ptr<ITranscodingClientCallback>& callback,
+ TranscodingLogger::SessionEndedReason* failureReason /* nonnull */,
const std::shared_ptr<ndk::ScopedAParcel>& pausedState = nullptr);
void cleanup();
+ void logSessionEnded(const TranscodingLogger::SessionEndedReason& reason, int error);
void reportError(ClientIdType clientId, SessionIdType sessionId, media_status_t err);
void queueEvent(Event::Type type, ClientIdType clientId, SessionIdType sessionId,
const std::function<void()> runnable, int32_t arg = 0);
diff --git a/media/libmediatranscoding/include/media/TranscodingLogger.h b/media/libmediatranscoding/include/media/TranscodingLogger.h
new file mode 100644
index 0000000..dc24551
--- /dev/null
+++ b/media/libmediatranscoding/include/media/TranscodingLogger.h
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_MEDIA_TRANSCODING_LOGGER_H
+#define ANDROID_MEDIA_TRANSCODING_LOGGER_H
+
+#include <media/NdkMediaFormat.h>
+#include <utils/Condition.h>
+
+#include <chrono>
+#include <memory>
+#include <mutex>
+#include <queue>
+
+namespace android {
+
+/** Class for logging transcoding events. */
+class TranscodingLogger {
+public:
+ /** The maximum number of atoms pushed to statsd per day. */
+ static constexpr int kMaxAtomsPerDay = 50;
+
+ /** The maximum number of successful transcoding atoms pushed to statsd per day. */
+ static constexpr int kMaxSuccessfulAtomsPerDay = 35;
+
+ /** Reason transcoding session ended. Maps to MediaTranscodingSessionEnded atom's Reason. */
+ enum SessionEndedReason {
+ UNKNOWN = 0,
+ FINISHED,
+ ERROR,
+ PAUSED,
+ CANCELLED,
+ START_FAILED,
+ RESUME_FAILED,
+ CREATE_FAILED,
+ CONFIG_SRC_FAILED,
+ CONFIG_DST_FAILED,
+ CONFIG_TRACK_FAILED,
+ OPEN_SRC_FD_FAILED,
+ OPEN_DST_FD_FAILED,
+ NO_TRACKS,
+ };
+
+ TranscodingLogger();
+ ~TranscodingLogger() = default;
+
+ /**
+ * Logs a transcoding session ended event (MediaTranscodingSessionEnded atom).
+ * @param reason Reason for the transcoding session to end.
+ * @param callingUid UID of the caller connecting to the transcoding service.
+ * @param status Status (error code) of the transcoding session.
+ * @param duration Duration of the transcoding session.
+ * @param srcFormat The source video track format.
+ * @param dstFormat The destination video track format.
+ */
+ void logSessionEnded(enum SessionEndedReason reason, uid_t callingUid, int status,
+ std::chrono::microseconds duration, AMediaFormat* srcFormat,
+ AMediaFormat* dstFormat);
+
+private:
+ friend class TranscodingLoggerTest;
+
+ // Function prototype for writing out the session ended atom.
+ using SessionEndedAtomWriter = std::function<int(
+ int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, char const*, int32_t,
+ int32_t, int32_t, int32_t, bool arg12, int32_t, int32_t, char const*, bool)>;
+
+ std::mutex mLock;
+ std::queue<std::pair<std::chrono::steady_clock::time_point, int>> mLastLoggedAtoms
+ GUARDED_BY(mLock);
+ uint32_t mSuccessfulCount = 0;
+ SessionEndedAtomWriter mSessionEndedAtomWriter;
+
+ void logSessionEnded(const std::chrono::steady_clock::time_point& now,
+ enum SessionEndedReason reason, uid_t callingUid, int status,
+ std::chrono::microseconds duration, AMediaFormat* srcFormat,
+ AMediaFormat* dstFormat);
+ bool shouldLogAtom(const std::chrono::steady_clock::time_point& now, int status);
+ // Used for testing to validate what gets sent to statsd.
+ void setSessionEndedAtomWriter(const SessionEndedAtomWriter& writer);
+};
+
+} // namespace android
+#endif // ANDROID_MEDIA_TRANSCODING_LOGGER_H
diff --git a/media/libmediatranscoding/include/media/TranscodingSessionController.h b/media/libmediatranscoding/include/media/TranscodingSessionController.h
index 34e9506..b2d6f0a 100644
--- a/media/libmediatranscoding/include/media/TranscodingSessionController.h
+++ b/media/libmediatranscoding/include/media/TranscodingSessionController.h
@@ -48,7 +48,7 @@
virtual ~TranscodingSessionController();
// ControllerClientInterface
- bool submit(ClientIdType clientId, SessionIdType sessionId, uid_t uid,
+ bool submit(ClientIdType clientId, SessionIdType sessionId, uid_t callingUid, uid_t clientUid,
const TranscodingRequestParcel& request,
const std::weak_ptr<ITranscodingClientCallback>& clientCallback) override;
bool cancel(ClientIdType clientId, SessionIdType sessionId) override;
@@ -93,7 +93,18 @@
using SessionKeyType = std::pair<ClientIdType, SessionIdType>;
using SessionQueueType = std::list<SessionKeyType>;
using TranscoderFactoryType = std::function<std::shared_ptr<TranscoderInterface>(
- const std::shared_ptr<TranscoderCallbackInterface>&, int64_t)>;
+ const std::shared_ptr<TranscoderCallbackInterface>&)>;
+
+ struct ControllerConfig {
+ // Watchdog timeout.
+ int64_t watchdogTimeoutUs = 3000000LL;
+ // Threshold of time between finish/start below which a back-to-back start is counted.
+ int32_t pacerBurstThresholdMs = 1000;
+ // Maximum allowed back-to-back start count.
+ int32_t pacerBurstCountQuota = 10;
+ // Maximum allowed back-to-back running time.
+ int32_t pacerBurstTimeQuotaSeconds = 180; // 3-min
+ };
struct Session {
enum State {
@@ -106,15 +117,17 @@
FINISHED,
CANCELED,
ERROR,
+ DROPPED_BY_PACER,
};
SessionKeyType key;
- uid_t uid;
- int32_t lastProgress;
- int32_t pauseCount;
- std::chrono::time_point<std::chrono::system_clock> stateEnterTime;
- std::chrono::microseconds waitingTime;
- std::chrono::microseconds runningTime;
- std::chrono::microseconds pausedTime;
+ uid_t clientUid;
+ uid_t callingUid;
+ int32_t lastProgress = 0;
+ int32_t pauseCount = 0;
+ std::chrono::time_point<std::chrono::steady_clock> stateEnterTime;
+ std::chrono::microseconds waitingTime{0};
+ std::chrono::microseconds runningTime{0};
+ std::chrono::microseconds pausedTime{0};
TranscodingRequest request;
std::weak_ptr<ITranscodingClientCallback> callback;
@@ -122,12 +135,16 @@
// Must use setState to change state.
void setState(Session::State state);
State getState() const { return state; }
+ bool isRunning() { return state == RUNNING; }
private:
State state = INVALID;
};
struct Watchdog;
+ struct Pacer;
+
+ ControllerConfig mConfig;
// TODO(chz): call transcoder without global lock.
// Use mLock for all entrypoints for now.
@@ -155,12 +172,14 @@
bool mThermalThrottling;
std::list<Session> mSessionHistory;
std::shared_ptr<Watchdog> mWatchdog;
+ std::shared_ptr<Pacer> mPacer;
// Only allow MediaTranscodingService and unit tests to instantiate.
TranscodingSessionController(const TranscoderFactoryType& transcoderFactory,
const std::shared_ptr<UidPolicyInterface>& uidPolicy,
const std::shared_ptr<ResourcePolicyInterface>& resourcePolicy,
- const std::shared_ptr<ThermalPolicyInterface>& thermalPolicy);
+ const std::shared_ptr<ThermalPolicyInterface>& thermalPolicy,
+ const ControllerConfig* config = nullptr);
void dumpSession_l(const Session& session, String8& result, bool closedSession = false);
Session* getTopSession_l();
diff --git a/media/libmediatranscoding/tests/Android.bp b/media/libmediatranscoding/tests/Android.bp
index 06b9b17..603611a 100644
--- a/media/libmediatranscoding/tests/Android.bp
+++ b/media/libmediatranscoding/tests/Android.bp
@@ -72,3 +72,15 @@
srcs: ["AdjustableMaxPriorityQueue_tests.cpp"],
}
+
+//
+// TranscodingLogger unit test
+//
+cc_test {
+ name: "TranscodingLogger_tests",
+ defaults: ["libmediatranscoding_test_defaults"],
+ shared_libs: ["libmediandk", "libstatssocket#30"],
+ static_libs: ["libmediatranscoder", "libstatslog_media"],
+
+ srcs: ["TranscodingLogger_tests.cpp"],
+}
diff --git a/media/libmediatranscoding/tests/TranscodingClientManager_tests.cpp b/media/libmediatranscoding/tests/TranscodingClientManager_tests.cpp
index 1a50923..57a2e27 100644
--- a/media/libmediatranscoding/tests/TranscodingClientManager_tests.cpp
+++ b/media/libmediatranscoding/tests/TranscodingClientManager_tests.cpp
@@ -135,7 +135,7 @@
virtual ~TestController() { ALOGI("TestController Destroyed"); }
- bool submit(ClientIdType clientId, SessionIdType sessionId, uid_t /*uid*/,
+ bool submit(ClientIdType clientId, SessionIdType sessionId, uid_t /*callingUid*/, uid_t /*uid*/,
const TranscodingRequestParcel& request,
const std::weak_ptr<ITranscodingClientCallback>& clientCallback) override {
SessionKeyType sessionKey = std::make_pair(clientId, sessionId);
diff --git a/media/libmediatranscoding/tests/TranscodingLogger_tests.cpp b/media/libmediatranscoding/tests/TranscodingLogger_tests.cpp
new file mode 100644
index 0000000..39e5cd4
--- /dev/null
+++ b/media/libmediatranscoding/tests/TranscodingLogger_tests.cpp
@@ -0,0 +1,286 @@
+/*
+ * 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.
+ */
+
+// Unit Test for TranscodingLogger
+
+// #define LOG_NDEBUG 0
+#define LOG_TAG "TranscodingLoggerTest"
+
+#include <android-base/logging.h>
+#include <gtest/gtest.h>
+#include <media/NdkCommon.h>
+#include <media/TranscodingLogger.h>
+#include <statslog_media.h>
+#include <utils/Log.h>
+
+#include <chrono>
+
+namespace android {
+
+using Reason = TranscodingLogger::SessionEndedReason;
+
+// Data structure corresponding to MediaTranscodingEnded atom.
+struct SessionEndedAtom {
+ SessionEndedAtom(int32_t atomCode, int32_t reason, int32_t callingUid, int32_t status,
+ int32_t transcoderFps, int32_t srcWidth, int32_t srcHeight,
+ char const* srcMime, int32_t srcProfile, int32_t srcLevel, int32_t srcFps,
+ int32_t srcDurationMs, bool srcIsHdr, int32_t dstWidth, int32_t dstHeight,
+ char const* dstMime, bool dstIsHdr)
+ : atomCode(atomCode),
+ reason(reason),
+ callingUid(callingUid),
+ status(status),
+ transcoderFps(transcoderFps),
+ srcWidth(srcWidth),
+ srcHeight(srcHeight),
+ srcMime(srcMime),
+ srcProfile(srcProfile),
+ srcLevel(srcLevel),
+ srcFps(srcFps),
+ srcDurationMs(srcDurationMs),
+ srcIsHdr(srcIsHdr),
+ dstWidth(dstWidth),
+ dstHeight(dstHeight),
+ dstMime(dstMime),
+ dstIsHdr(dstIsHdr) {}
+
+ int32_t atomCode;
+ int32_t reason;
+ int32_t callingUid;
+ int32_t status;
+ int32_t transcoderFps;
+ int32_t srcWidth;
+ int32_t srcHeight;
+ std::string srcMime;
+ int32_t srcProfile;
+ int32_t srcLevel;
+ int32_t srcFps;
+ int32_t srcDurationMs;
+ bool srcIsHdr;
+ int32_t dstWidth;
+ int32_t dstHeight;
+ std::string dstMime;
+ bool dstIsHdr;
+};
+
+// Default configuration values.
+static constexpr int32_t kDefaultCallingUid = 1;
+static constexpr std::chrono::microseconds kDefaultTranscodeDuration = std::chrono::seconds{2};
+
+static constexpr int32_t kDefaultSrcWidth = 1920;
+static constexpr int32_t kDefaultSrcHeight = 1080;
+static const std::string kDefaultSrcMime{AMEDIA_MIMETYPE_VIDEO_HEVC};
+static constexpr int32_t kDefaultSrcProfile = 1; // HEVC Main
+static constexpr int32_t kDefaultSrcLevel = 65536; // HEVCMainTierLevel51
+static constexpr int32_t kDefaultSrcFps = 30;
+static constexpr int32_t kDefaultSrcFrameCount = 120;
+static constexpr int64_t kDefaultSrcDurationUs = 1000000 * kDefaultSrcFrameCount / kDefaultSrcFps;
+
+static constexpr int32_t kDefaultDstWidth = 1280;
+static constexpr int32_t kDefaultDstHeight = 720;
+static const std::string kDefaultDstMime{AMEDIA_MIMETYPE_VIDEO_AVC};
+
+// Util for creating a default source video format.
+static AMediaFormat* CreateSrcFormat() {
+ AMediaFormat* fmt = AMediaFormat_new();
+ AMediaFormat_setInt32(fmt, AMEDIAFORMAT_KEY_WIDTH, kDefaultSrcWidth);
+ AMediaFormat_setInt32(fmt, AMEDIAFORMAT_KEY_HEIGHT, kDefaultSrcHeight);
+ AMediaFormat_setString(fmt, AMEDIAFORMAT_KEY_MIME, kDefaultSrcMime.c_str());
+ AMediaFormat_setInt32(fmt, AMEDIAFORMAT_KEY_PROFILE, kDefaultSrcProfile);
+ AMediaFormat_setInt32(fmt, AMEDIAFORMAT_KEY_LEVEL, kDefaultSrcLevel);
+ AMediaFormat_setInt32(fmt, AMEDIAFORMAT_KEY_FRAME_RATE, kDefaultSrcFps);
+ AMediaFormat_setInt32(fmt, AMEDIAFORMAT_KEY_FRAME_COUNT, kDefaultSrcFrameCount);
+ AMediaFormat_setInt64(fmt, AMEDIAFORMAT_KEY_DURATION, kDefaultSrcDurationUs);
+ return fmt;
+}
+
+// Util for creating a default destination video format.
+static AMediaFormat* CreateDstFormat() {
+ AMediaFormat* fmt = AMediaFormat_new();
+ AMediaFormat_setInt32(fmt, AMEDIAFORMAT_KEY_WIDTH, kDefaultDstWidth);
+ AMediaFormat_setInt32(fmt, AMEDIAFORMAT_KEY_HEIGHT, kDefaultDstHeight);
+ AMediaFormat_setString(fmt, AMEDIAFORMAT_KEY_MIME, kDefaultDstMime.c_str());
+ return fmt;
+}
+
+class TranscodingLoggerTest : public ::testing::Test {
+public:
+ TranscodingLoggerTest() { ALOGI("TranscodingLoggerTest created"); }
+
+ void SetUp() override {
+ ALOGI("TranscodingLoggerTest set up");
+ mLogger.reset(new TranscodingLogger());
+ mLoggedAtoms.clear();
+ mSrcFormat.reset();
+ mDstFormat.reset();
+
+ // Set a custom atom writer that saves all data, so the test can validate it afterwards.
+ mLogger->setSessionEndedAtomWriter(
+ [=](int32_t atomCode, int32_t reason, int32_t callingUid, int32_t status,
+ int32_t transcoderFps, int32_t srcWidth, int32_t srcHeight, char const* srcMime,
+ int32_t srcProfile, int32_t srcLevel, int32_t srcFps, int32_t srcDurationMs,
+ bool srcIsHdr, int32_t dstWidth, int32_t dstHeight, char const* dstMime,
+ bool dstIsHdr) -> int {
+ mLoggedAtoms.emplace_back(atomCode, reason, callingUid, status, transcoderFps,
+ srcWidth, srcHeight, srcMime, srcProfile, srcLevel,
+ srcFps, srcDurationMs, srcIsHdr, dstWidth, dstHeight,
+ dstMime, dstIsHdr);
+ return 0;
+ });
+ }
+
+ void logSession(const std::chrono::steady_clock::time_point& time, Reason reason, int status,
+ AMediaFormat* srcFormat, AMediaFormat* dstFormat) {
+ mLogger->logSessionEnded(time, reason, kDefaultCallingUid, status,
+ kDefaultTranscodeDuration, srcFormat, dstFormat);
+ }
+
+ void logSession(const std::chrono::steady_clock::time_point& time, Reason reason, int status) {
+ if (!mSrcFormat) {
+ mSrcFormat = std::shared_ptr<AMediaFormat>(CreateSrcFormat(), &AMediaFormat_delete);
+ }
+ if (!mDstFormat) {
+ mDstFormat = std::shared_ptr<AMediaFormat>(CreateDstFormat(), &AMediaFormat_delete);
+ }
+ logSession(time, reason, status, mSrcFormat.get(), mDstFormat.get());
+ }
+
+ void logSessionFinished(const std::chrono::steady_clock::time_point& time) {
+ logSession(time, Reason::FINISHED, 0);
+ }
+
+ void logSessionFailed(const std::chrono::steady_clock::time_point& time) {
+ logSession(time, Reason::ERROR, AMEDIA_ERROR_UNKNOWN);
+ }
+
+ int logCount() const { return mLoggedAtoms.size(); }
+
+ void validateLatestAtom(Reason reason, int status, bool passthrough = false) {
+ const SessionEndedAtom& atom = mLoggedAtoms.back();
+
+ EXPECT_EQ(atom.atomCode, android::media::stats::MEDIA_TRANSCODING_SESSION_ENDED);
+ EXPECT_EQ(atom.reason, static_cast<int>(reason));
+ EXPECT_EQ(atom.callingUid, kDefaultCallingUid);
+ EXPECT_EQ(atom.status, status);
+ EXPECT_EQ(atom.srcWidth, kDefaultSrcWidth);
+ EXPECT_EQ(atom.srcHeight, kDefaultSrcHeight);
+ EXPECT_EQ(atom.srcMime, kDefaultSrcMime);
+ EXPECT_EQ(atom.srcProfile, kDefaultSrcProfile);
+ EXPECT_EQ(atom.srcLevel, kDefaultSrcLevel);
+ EXPECT_EQ(atom.srcFps, kDefaultSrcFps);
+ EXPECT_EQ(atom.srcDurationMs, kDefaultSrcDurationUs / 1000);
+ EXPECT_FALSE(atom.srcIsHdr);
+ EXPECT_EQ(atom.dstWidth, passthrough ? kDefaultSrcWidth : kDefaultDstWidth);
+ EXPECT_EQ(atom.dstHeight, passthrough ? kDefaultSrcHeight : kDefaultDstHeight);
+ EXPECT_EQ(atom.dstMime, passthrough ? "passthrough" : kDefaultDstMime);
+ EXPECT_FALSE(atom.dstIsHdr);
+
+ // Transcoder frame rate is only present on successful sessions.
+ if (status == AMEDIA_OK) {
+ std::chrono::duration<double> seconds{kDefaultTranscodeDuration};
+ const int32_t transcoderFps =
+ static_cast<int32_t>(kDefaultSrcFrameCount / seconds.count());
+ EXPECT_EQ(atom.transcoderFps, transcoderFps);
+ } else {
+ EXPECT_EQ(atom.transcoderFps, -1);
+ }
+ }
+
+ void TearDown() override { ALOGI("TranscodingLoggerTest tear down"); }
+ ~TranscodingLoggerTest() { ALOGD("TranscodingLoggerTest destroyed"); }
+
+ std::shared_ptr<TranscodingLogger> mLogger;
+ std::vector<SessionEndedAtom> mLoggedAtoms;
+
+ std::shared_ptr<AMediaFormat> mSrcFormat;
+ std::shared_ptr<AMediaFormat> mDstFormat;
+};
+
+TEST_F(TranscodingLoggerTest, TestDailyLogQuota) {
+ ALOGD("TestDailyLogQuota");
+ auto start = std::chrono::steady_clock::now();
+
+ EXPECT_LT(TranscodingLogger::kMaxSuccessfulAtomsPerDay, TranscodingLogger::kMaxAtomsPerDay);
+
+ // 1. Check that the first kMaxSuccessfulAtomsPerDay successful atoms are logged.
+ for (int i = 0; i < TranscodingLogger::kMaxSuccessfulAtomsPerDay; ++i) {
+ logSessionFinished(start + std::chrono::seconds{i});
+ EXPECT_EQ(logCount(), i + 1);
+ }
+
+ // 2. Check that subsequent successful atoms within the same 24h interval are not logged.
+ for (int i = 1; i < 24; ++i) {
+ logSessionFinished(start + std::chrono::hours{i});
+ EXPECT_EQ(logCount(), TranscodingLogger::kMaxSuccessfulAtomsPerDay);
+ }
+
+ // 3. Check that failed atoms are logged up to kMaxAtomsPerDay.
+ for (int i = TranscodingLogger::kMaxSuccessfulAtomsPerDay;
+ i < TranscodingLogger::kMaxAtomsPerDay; ++i) {
+ logSessionFailed(start + std::chrono::seconds{i});
+ EXPECT_EQ(logCount(), i + 1);
+ }
+
+ // 4. Check that subsequent failed atoms within the same 24h interval are not logged.
+ for (int i = 1; i < 24; ++i) {
+ logSessionFailed(start + std::chrono::hours{i});
+ EXPECT_EQ(logCount(), TranscodingLogger::kMaxAtomsPerDay);
+ }
+
+ // 5. Check that failed and successful atoms are logged again after 24h.
+ logSessionFinished(start + std::chrono::hours{24});
+ EXPECT_EQ(logCount(), TranscodingLogger::kMaxAtomsPerDay + 1);
+
+ logSessionFailed(start + std::chrono::hours{24} + std::chrono::seconds{1});
+ EXPECT_EQ(logCount(), TranscodingLogger::kMaxAtomsPerDay + 2);
+}
+
+TEST_F(TranscodingLoggerTest, TestNullFormats) {
+ ALOGD("TestNullFormats");
+ auto srcFormat = std::shared_ptr<AMediaFormat>(CreateSrcFormat(), &AMediaFormat_delete);
+ auto dstFormat = std::shared_ptr<AMediaFormat>(CreateDstFormat(), &AMediaFormat_delete);
+ auto now = std::chrono::steady_clock::now();
+
+ // Source format null, should not log.
+ logSession(now, Reason::FINISHED, AMEDIA_OK, nullptr /*srcFormat*/, dstFormat.get());
+ EXPECT_EQ(logCount(), 0);
+
+ // Both formats null, should not log.
+ logSession(now, Reason::FINISHED, AMEDIA_OK, nullptr /*srcFormat*/, nullptr /*dstFormat*/);
+ EXPECT_EQ(logCount(), 0);
+
+ // Destination format null (passthrough mode), should log.
+ logSession(now, Reason::FINISHED, AMEDIA_OK, srcFormat.get(), nullptr /*dstFormat*/);
+ EXPECT_EQ(logCount(), 1);
+ validateLatestAtom(Reason::FINISHED, AMEDIA_OK, true /*passthrough*/);
+}
+
+TEST_F(TranscodingLoggerTest, TestAtomContentCorrectness) {
+ ALOGD("TestAtomContentCorrectness");
+ auto now = std::chrono::steady_clock::now();
+
+ // Log and validate a failure.
+ logSession(now, Reason::ERROR, AMEDIA_ERROR_MALFORMED);
+ EXPECT_EQ(logCount(), 1);
+ validateLatestAtom(Reason::ERROR, AMEDIA_ERROR_MALFORMED);
+
+ // Log and validate a success.
+ logSession(now, Reason::FINISHED, AMEDIA_OK);
+ EXPECT_EQ(logCount(), 2);
+ validateLatestAtom(Reason::FINISHED, AMEDIA_OK);
+}
+
+} // namespace android
diff --git a/media/libmediatranscoding/tests/TranscodingSessionController_tests.cpp b/media/libmediatranscoding/tests/TranscodingSessionController_tests.cpp
index 2e9daee..560d1fe 100644
--- a/media/libmediatranscoding/tests/TranscodingSessionController_tests.cpp
+++ b/media/libmediatranscoding/tests/TranscodingSessionController_tests.cpp
@@ -118,12 +118,12 @@
class TestTranscoder : public TranscoderInterface {
public:
- TestTranscoder() : mLastError(TranscodingErrorCode::kUnknown), mGeneration(0) {}
+ TestTranscoder() : mGeneration(0) {}
virtual ~TestTranscoder() {}
// TranscoderInterface
void start(ClientIdType clientId, SessionIdType sessionId,
- const TranscodingRequestParcel& /*request*/,
+ const TranscodingRequestParcel& /*request*/, uid_t /*callingUid*/,
const std::shared_ptr<ITranscodingClientCallback>& /*clientCallback*/) override {
append(Start(clientId, sessionId));
}
@@ -131,7 +131,7 @@
append(Pause(clientId, sessionId));
}
void resume(ClientIdType clientId, SessionIdType sessionId,
- const TranscodingRequestParcel& /*request*/,
+ const TranscodingRequestParcel& /*request*/, uid_t /*callingUid*/,
const std::shared_ptr<ITranscodingClientCallback>& /*clientCallback*/) override {
append(Resume(clientId, sessionId));
}
@@ -152,19 +152,6 @@
mGeneration++;
}
- TranscodingErrorCode getLastError() {
- std::scoped_lock lock{mLock};
- // Clear last error.
- TranscodingErrorCode result = mLastError;
- mLastError = TranscodingErrorCode::kNoError;
- return result;
- }
-
- int32_t getGeneration() {
- std::scoped_lock lock{mLock};
- return mGeneration;
- }
-
struct Event {
enum { NoEvent, Start, Pause, Resume, Stop, Finished, Failed, Abandon } type;
ClientIdType clientId;
@@ -195,7 +182,7 @@
// Error is sticky, non-error event will not erase it, only getLastError()
// clears last error.
if (err != TranscodingErrorCode::kNoError) {
- mLastError = err;
+ mLastErrorQueue.push_back(err);
}
mCondition.notify_one();
}
@@ -218,12 +205,27 @@
return mPoppedEvent;
}
+ TranscodingErrorCode getLastError() {
+ std::scoped_lock lock{mLock};
+ if (mLastErrorQueue.empty()) {
+ return TranscodingErrorCode::kNoError;
+ }
+ TranscodingErrorCode err = mLastErrorQueue.front();
+ mLastErrorQueue.pop_front();
+ return err;
+ }
+
+ int32_t getGeneration() {
+ std::scoped_lock lock{mLock};
+ return mGeneration;
+ }
+
private:
std::mutex mLock;
std::condition_variable mCondition;
Event mPoppedEvent;
std::list<Event> mEventQueue;
- TranscodingErrorCode mLastError;
+ std::list<TranscodingErrorCode> mLastErrorQueue;
int32_t mGeneration;
};
@@ -291,16 +293,21 @@
mUidPolicy.reset(new TestUidPolicy());
mResourcePolicy.reset(new TestResourcePolicy());
mThermalPolicy.reset(new TestThermalPolicy());
+ // Overrid default burst params with shorter values for testing.
+ TranscodingSessionController::ControllerConfig config = {
+ .pacerBurstThresholdMs = 500,
+ .pacerBurstCountQuota = 10,
+ .pacerBurstTimeQuotaSeconds = 3,
+ };
mController.reset(new TranscodingSessionController(
- [this](const std::shared_ptr<TranscoderCallbackInterface>& /*cb*/,
- int64_t /*heartBeatIntervalUs*/) {
+ [this](const std::shared_ptr<TranscoderCallbackInterface>& /*cb*/) {
// Here we require that the SessionController clears out all its refcounts of
// the transcoder object when it calls create.
EXPECT_EQ(mTranscoder.use_count(), 1);
mTranscoder->onCreated();
return mTranscoder;
},
- mUidPolicy, mResourcePolicy, mThermalPolicy));
+ mUidPolicy, mResourcePolicy, mThermalPolicy, &config));
mUidPolicy->setCallback(mController);
// Set priority only, ignore other fields for now.
@@ -328,6 +335,40 @@
EXPECT_EQ(mTranscoder.use_count(), 2);
}
+ void testPacerHelper(int numSubmits, int sessionDurationMs, int expectedSuccess,
+ bool pauseLastSuccessSession = false) {
+ for (int i = 0; i < numSubmits; i++) {
+ mController->submit(CLIENT(0), SESSION(i), UID(0), UID(0),
+ mRealtimeRequest, mClientCallback0);
+ }
+ for (int i = 0; i < expectedSuccess; i++) {
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(i)));
+ if ((i == expectedSuccess - 1) && pauseLastSuccessSession) {
+ // Insert a pause of 3 sec to the last success running session
+ mController->onThrottlingStarted();
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), SESSION(i)));
+ sleep(3);
+ mController->onThrottlingStopped();
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), SESSION(i)));
+ }
+ usleep(sessionDurationMs * 1000);
+ // Test half of Finish and half of Error, both should be counted as burst runs.
+ if (i & 1) {
+ mController->onFinish(CLIENT(0), SESSION(i));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(0), SESSION(i)));
+ } else {
+ mController->onError(CLIENT(0), SESSION(i), TranscodingErrorCode::kUnknown);
+ EXPECT_EQ(mTranscoder->popEvent(100000),
+ TestTranscoder::Failed(CLIENT(0), SESSION(i)));
+ EXPECT_EQ(mTranscoder->getLastError(), TranscodingErrorCode::kUnknown);
+ }
+ }
+ for (int i = expectedSuccess; i < numSubmits; i++) {
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Failed(CLIENT(0), SESSION(i)));
+ EXPECT_EQ(mTranscoder->getLastError(), TranscodingErrorCode::kDroppedByService);
+ }
+ }
+
std::shared_ptr<TestTranscoder> mTranscoder;
std::shared_ptr<TestUidPolicy> mUidPolicy;
std::shared_ptr<TestResourcePolicy> mResourcePolicy;
@@ -349,32 +390,32 @@
// Submit offline session to CLIENT(0) in UID(0).
// Should start immediately (because this is the only session).
- mController->submit(CLIENT(0), SESSION(0), UID(0), mOfflineRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(0), UID(0), UID(0), mOfflineRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), 0));
// Submit real-time session to CLIENT(0).
// Should pause offline session and start new session, even if UID(0) is not on top.
- mController->submit(CLIENT(0), SESSION(1), UID(0), mRealtimeRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(1), UID(0), UID(0), mRealtimeRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), SESSION(0)));
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(1)));
// Submit real-time session to CLIENT(0), should be queued after the previous session.
- mController->submit(CLIENT(0), SESSION(2), UID(0), mRealtimeRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(2), UID(0), UID(0), mRealtimeRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
// Submit real-time session to CLIENT(1) in same uid, should be queued after the previous
// session.
- mController->submit(CLIENT(1), SESSION(0), UID(0), mRealtimeRequest, mClientCallback1);
+ mController->submit(CLIENT(1), SESSION(0), UID(1), UID(0), mRealtimeRequest, mClientCallback1);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
// Submit real-time session to CLIENT(2) in UID(1).
// Should pause previous session and start new session, because UID(1) is (has been) top.
- mController->submit(CLIENT(2), SESSION(0), UID(1), mRealtimeRequest, mClientCallback2);
+ mController->submit(CLIENT(2), SESSION(0), UID(2), UID(1), mRealtimeRequest, mClientCallback2);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), SESSION(1)));
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), SESSION(0)));
// Submit offline session, shouldn't generate any event.
- mController->submit(CLIENT(2), SESSION(1), UID(1), mOfflineRequest, mClientCallback2);
+ mController->submit(CLIENT(2), SESSION(1), UID(2), UID(1), mOfflineRequest, mClientCallback2);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
// Bring UID(0) to top.
@@ -388,15 +429,15 @@
ALOGD("TestCancelSession");
// Submit real-time session SESSION(0), should start immediately.
- mController->submit(CLIENT(0), SESSION(0), UID(0), mRealtimeRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(0), UID(0), UID(0), mRealtimeRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(0)));
// Submit real-time session SESSION(1), should not start.
- mController->submit(CLIENT(0), SESSION(1), UID(0), mRealtimeRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(1), UID(0), UID(0), mRealtimeRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
// Submit offline session SESSION(2), should not start.
- mController->submit(CLIENT(0), SESSION(2), UID(0), mOfflineRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(2), UID(0), UID(0), mOfflineRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
// Cancel queued real-time session.
@@ -408,7 +449,7 @@
EXPECT_TRUE(mController->cancel(CLIENT(0), SESSION(2)));
// Submit offline session SESSION(3), shouldn't cause any event.
- mController->submit(CLIENT(0), SESSION(3), UID(0), mOfflineRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(3), UID(0), UID(0), mOfflineRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
// Cancel running real-time session SESSION(0).
@@ -420,7 +461,7 @@
// Submit real-time session SESSION(4), offline SESSION(3) should pause and SESSION(4)
// should start.
- mController->submit(CLIENT(0), SESSION(4), UID(0), mRealtimeRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(4), UID(0), UID(0), mRealtimeRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), SESSION(3)));
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(4)));
@@ -438,16 +479,16 @@
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
// Submit offline session SESSION(0), should start immediately.
- mController->submit(CLIENT(0), SESSION(0), UID(0), mOfflineRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(0), UID(0), UID(0), mOfflineRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(0)));
// Submit real-time session SESSION(1), should pause offline session and start immediately.
- mController->submit(CLIENT(0), SESSION(1), UID(0), mRealtimeRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(1), UID(0), UID(0), mRealtimeRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), SESSION(0)));
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(1)));
// Submit real-time session SESSION(2), should not start.
- mController->submit(CLIENT(0), SESSION(2), UID(0), mRealtimeRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(2), UID(0), UID(0), mRealtimeRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
// Finish when the session never started, should be ignored.
@@ -458,7 +499,7 @@
mUidPolicy->setTop(UID(1));
// Submit real-time session to CLIENT(1) in UID(1), should pause previous session and start
// new session.
- mController->submit(CLIENT(1), SESSION(0), UID(1), mRealtimeRequest, mClientCallback1);
+ mController->submit(CLIENT(1), SESSION(0), UID(1), UID(1), mRealtimeRequest, mClientCallback1);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), SESSION(1)));
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(1), SESSION(0)));
@@ -495,16 +536,16 @@
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
// Submit offline session SESSION(0), should start immediately.
- mController->submit(CLIENT(0), SESSION(0), UID(0), mOfflineRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(0), UID(0), UID(0), mOfflineRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(0)));
// Submit real-time session SESSION(1), should pause offline session and start immediately.
- mController->submit(CLIENT(0), SESSION(1), UID(0), mRealtimeRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(1), UID(0), UID(0), mRealtimeRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), SESSION(0)));
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(1)));
// Submit real-time session SESSION(2), should not start.
- mController->submit(CLIENT(0), SESSION(2), UID(0), mRealtimeRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(2), UID(0), UID(0), mRealtimeRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
// Fail when the session never started, should be ignored.
@@ -515,7 +556,7 @@
mUidPolicy->setTop(UID(1));
// Submit real-time session to CLIENT(1) in UID(1), should pause previous session and start
// new session.
- mController->submit(CLIENT(1), SESSION(0), UID(1), mRealtimeRequest, mClientCallback1);
+ mController->submit(CLIENT(1), SESSION(0), UID(1), UID(1), mRealtimeRequest, mClientCallback1);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), SESSION(1)));
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(1), SESSION(0)));
@@ -523,15 +564,18 @@
// Should still be propagated to client, but shouldn't trigger any new start.
mController->onError(CLIENT(0), SESSION(1), TranscodingErrorCode::kUnknown);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Failed(CLIENT(0), SESSION(1)));
+ EXPECT_EQ(mTranscoder->getLastError(), TranscodingErrorCode::kUnknown);
// Fail running real-time session, should start next real-time session in queue.
mController->onError(CLIENT(1), SESSION(0), TranscodingErrorCode::kUnknown);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Failed(CLIENT(1), SESSION(0)));
+ EXPECT_EQ(mTranscoder->getLastError(), TranscodingErrorCode::kUnknown);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(2)));
// Fail running real-time session, should resume next session (offline session) in queue.
mController->onError(CLIENT(0), SESSION(2), TranscodingErrorCode::kUnknown);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Failed(CLIENT(0), SESSION(2)));
+ EXPECT_EQ(mTranscoder->getLastError(), TranscodingErrorCode::kUnknown);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), SESSION(0)));
// Fail running offline session, and test error code propagation.
@@ -549,11 +593,11 @@
// Start with unspecified top UID.
// Submit real-time session to CLIENT(0), session should start immediately.
- mController->submit(CLIENT(0), SESSION(0), UID(0), mRealtimeRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(0), UID(0), UID(0), mRealtimeRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(0)));
// Submit offline session to CLIENT(0), should not start.
- mController->submit(CLIENT(1), SESSION(0), UID(0), mOfflineRequest, mClientCallback1);
+ mController->submit(CLIENT(1), SESSION(0), UID(1), UID(0), mOfflineRequest, mClientCallback1);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
// Move UID(1) to top.
@@ -562,7 +606,7 @@
// Submit real-time session to CLIENT(2) in different uid UID(1).
// Should pause previous session and start new session.
- mController->submit(CLIENT(2), SESSION(0), UID(1), mRealtimeRequest, mClientCallback2);
+ mController->submit(CLIENT(2), SESSION(0), UID(2), UID(1), mRealtimeRequest, mClientCallback2);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), SESSION(0)));
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), SESSION(0)));
@@ -591,11 +635,11 @@
// Start with unspecified top UID.
// Submit real-time session to CLIENT(0), session should start immediately.
- mController->submit(CLIENT(0), SESSION(0), UID(0), mRealtimeRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(0), UID(0), UID(0), mRealtimeRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(0)));
// Submit offline session to CLIENT(0), should not start.
- mController->submit(CLIENT(1), SESSION(0), UID(0), mOfflineRequest, mClientCallback1);
+ mController->submit(CLIENT(1), SESSION(0), UID(1), UID(0), mOfflineRequest, mClientCallback1);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
// Set UID(0), UID(1) to top set.
@@ -605,7 +649,7 @@
// Submit real-time session to CLIENT(2) in different uid UID(1).
// UID(0) should pause and UID(1) should start.
- mController->submit(CLIENT(2), SESSION(0), UID(1), mRealtimeRequest, mClientCallback2);
+ mController->submit(CLIENT(2), SESSION(0), UID(2), UID(1), mRealtimeRequest, mClientCallback2);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), SESSION(0)));
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), SESSION(0)));
@@ -647,12 +691,12 @@
// Start with unspecified top UID.
// Submit real-time session to CLIENT(0), session should start immediately.
mRealtimeRequest.clientPid = PID(0);
- mController->submit(CLIENT(0), SESSION(0), UID(0), mRealtimeRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(0), UID(0), UID(0), mRealtimeRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(0)));
// Submit offline session to CLIENT(0), should not start.
mOfflineRequest.clientPid = PID(0);
- mController->submit(CLIENT(1), SESSION(0), UID(0), mOfflineRequest, mClientCallback1);
+ mController->submit(CLIENT(1), SESSION(0), UID(1), UID(0), mOfflineRequest, mClientCallback1);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
// Move UID(1) to top.
@@ -662,7 +706,7 @@
// Submit real-time session to CLIENT(2) in different uid UID(1).
// Should pause previous session and start new session.
mRealtimeRequest.clientPid = PID(1);
- mController->submit(CLIENT(2), SESSION(0), UID(1), mRealtimeRequest, mClientCallback2);
+ mController->submit(CLIENT(2), SESSION(0), UID(2), UID(1), mRealtimeRequest, mClientCallback2);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), SESSION(0)));
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), SESSION(0)));
@@ -719,7 +763,7 @@
// Submit real-time session to CLIENT(3) in UID(2), session shouldn't start due to no resource.
mRealtimeRequest.clientPid = PID(2);
- mController->submit(CLIENT(3), SESSION(0), UID(2), mRealtimeRequest, mClientCallback3);
+ mController->submit(CLIENT(3), SESSION(0), UID(3), UID(2), mRealtimeRequest, mClientCallback3);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
// Signal resource available, CLIENT(3)'s session should start.
@@ -734,12 +778,12 @@
// Start with unspecified top UID.
// Submit real-time session to CLIENT(0), session should start immediately.
mRealtimeRequest.clientPid = PID(0);
- mController->submit(CLIENT(0), SESSION(0), UID(0), mRealtimeRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(0), UID(0), UID(0), mRealtimeRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(0)));
// Submit offline session to CLIENT(0), should not start.
mOfflineRequest.clientPid = PID(0);
- mController->submit(CLIENT(1), SESSION(0), UID(0), mOfflineRequest, mClientCallback1);
+ mController->submit(CLIENT(1), SESSION(0), UID(1), UID(0), mOfflineRequest, mClientCallback1);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
// Move UID(1) to top.
@@ -749,7 +793,7 @@
// Submit real-time session to CLIENT(2) in different uid UID(1).
// Should pause previous session and start new session.
mRealtimeRequest.clientPid = PID(1);
- mController->submit(CLIENT(2), SESSION(0), UID(1), mRealtimeRequest, mClientCallback2);
+ mController->submit(CLIENT(2), SESSION(0), UID(2), UID(1), mRealtimeRequest, mClientCallback2);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), SESSION(0)));
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), SESSION(0)));
@@ -788,7 +832,7 @@
mUidPolicy->setTop(UID(2));
// Submit real-time session to CLIENT(3) in UID(2), session shouldn't start during throttling.
mRealtimeRequest.clientPid = PID(2);
- mController->submit(CLIENT(3), SESSION(0), UID(2), mRealtimeRequest, mClientCallback3);
+ mController->submit(CLIENT(3), SESSION(0), UID(3), UID(2), mRealtimeRequest, mClientCallback3);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
// Throttling stops, CLIENT(3)'s session should start.
mController->onThrottlingStopped();
@@ -802,12 +846,12 @@
// Start with unspecified top UID.
// Submit real-time session to CLIENT(0), session should start immediately.
mRealtimeRequest.clientPid = PID(0);
- mController->submit(CLIENT(0), SESSION(0), UID(0), mRealtimeRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(0), UID(0), UID(0), mRealtimeRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(0)));
// Submit offline session to CLIENT(0), should not start.
mOfflineRequest.clientPid = PID(0);
- mController->submit(CLIENT(1), SESSION(0), UID(0), mOfflineRequest, mClientCallback1);
+ mController->submit(CLIENT(1), SESSION(0), UID(1), UID(0), mOfflineRequest, mClientCallback1);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
// Move UID(1) to top.
@@ -817,7 +861,7 @@
// Submit real-time session to CLIENT(2) in different uid UID(1).
// Should pause previous session and start new session.
mRealtimeRequest.clientPid = PID(1);
- mController->submit(CLIENT(2), SESSION(0), UID(1), mRealtimeRequest, mClientCallback2);
+ mController->submit(CLIENT(2), SESSION(0), UID(2), UID(1), mRealtimeRequest, mClientCallback2);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), SESSION(0)));
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), SESSION(0)));
@@ -854,29 +898,35 @@
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(2), SESSION(0)));
}
-TEST_F(TranscodingSessionControllerTest, TestTranscoderWatchdogTimeout) {
+TEST_F(TranscodingSessionControllerTest, TestTranscoderWatchdogNoHeartbeat) {
ALOGD("TestTranscoderWatchdogTimeout");
// Submit session to CLIENT(0) in UID(0).
// Should start immediately (because this is the only session).
- mController->submit(CLIENT(0), SESSION(0), UID(0), mRealtimeRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(0), UID(0), UID(0), mRealtimeRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(0)));
- int32_t expectedGen = 2;
// Test 1: If not sending keep-alive at all, timeout after 3 seconds.
- expectTimeout(CLIENT(0), SESSION(0), expectedGen++);
+ expectTimeout(CLIENT(0), SESSION(0), 2);
+}
+TEST_F(TranscodingSessionControllerTest, TestTranscoderWatchdogHeartbeat) {
// Test 2: No timeout as long as keep-alive coming; timeout after keep-alive stops.
- mController->submit(CLIENT(0), SESSION(1), UID(0), mRealtimeRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(1), UID(0), UID(0), mRealtimeRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(1)));
+
for (int i = 0; i < 5; i++) {
EXPECT_EQ(mTranscoder->popEvent(1000000), TestTranscoder::NoEvent);
mController->onHeartBeat(CLIENT(0), SESSION(1));
}
- expectTimeout(CLIENT(0), SESSION(1), expectedGen++);
+ expectTimeout(CLIENT(0), SESSION(1), 2);
+}
+
+TEST_F(TranscodingSessionControllerTest, TestTranscoderWatchdogDuringPause) {
+ int expectedGen = 2;
// Test 3a: No timeout for paused session even if no keep-alive is sent.
- mController->submit(CLIENT(0), SESSION(2), UID(0), mOfflineRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(2), UID(0), UID(0), mOfflineRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(2)));
// Trigger a pause by sending a resource lost.
mController->onResourceLost(CLIENT(0), SESSION(2));
@@ -886,12 +936,12 @@
expectTimeout(CLIENT(0), SESSION(2), expectedGen++);
// Test 3b: No timeout for paused session even if no keep-alive is sent.
- mController->submit(CLIENT(0), SESSION(3), UID(0), mOfflineRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(3), UID(0), UID(0), mOfflineRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(3)));
// Let the session run almost to timeout, to test timeout reset after pause.
EXPECT_EQ(mTranscoder->popEvent(2900000), TestTranscoder::NoEvent);
// Trigger a pause by submitting a higher-priority request.
- mController->submit(CLIENT(0), SESSION(4), UID(0), mRealtimeRequest, mClientCallback0);
+ mController->submit(CLIENT(0), SESSION(4), UID(0), UID(0), mRealtimeRequest, mClientCallback0);
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), SESSION(3)));
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(4)));
// Finish the higher-priority session, lower-priority session should resume,
@@ -902,4 +952,25 @@
expectTimeout(CLIENT(0), SESSION(3), expectedGen++);
}
+TEST_F(TranscodingSessionControllerTest, TestTranscoderPacerOverCountOnly) {
+ ALOGD("TestTranscoderPacerOverCountOnly");
+ testPacerHelper(12 /*numSubmits*/, 100 /*sessionDurationMs*/, 12 /*expectedSuccess*/);
+}
+
+TEST_F(TranscodingSessionControllerTest, TestTranscoderPacerOverTimeOnly) {
+ ALOGD("TestTranscoderPacerOverTimeOnly");
+ testPacerHelper(5 /*numSubmits*/, 1000 /*sessionDurationMs*/, 5 /*expectedSuccess*/);
+}
+
+TEST_F(TranscodingSessionControllerTest, TestTranscoderPacerOverQuota) {
+ ALOGD("TestTranscoderPacerOverQuota");
+ testPacerHelper(12 /*numSubmits*/, 400 /*sessionDurationMs*/, 10 /*expectedSuccess*/);
+}
+
+TEST_F(TranscodingSessionControllerTest, TestTranscoderPacerWithPause) {
+ ALOGD("TestTranscoderPacerDuringPause");
+ testPacerHelper(12 /*numSubmits*/, 400 /*sessionDurationMs*/, 10 /*expectedSuccess*/,
+ true /*pauseLastSuccessSession*/);
+}
+
} // namespace android
diff --git a/media/libmediatranscoding/tests/build_and_run_all_unit_tests.sh b/media/libmediatranscoding/tests/build_and_run_all_unit_tests.sh
index 5db9258..3cbf1dd 100644
--- a/media/libmediatranscoding/tests/build_and_run_all_unit_tests.sh
+++ b/media/libmediatranscoding/tests/build_and_run_all_unit_tests.sh
@@ -32,3 +32,7 @@
echo "testing TranscodingSessionController"
#adb shell /data/nativetest64/TranscodingSessionController_tests/TranscodingSessionController_tests
adb shell /data/nativetest/TranscodingSessionController_tests/TranscodingSessionController_tests
+
+echo "testing TranscodingLogger"
+#adb shell /data/nativetest64/TranscodingLogger_tests/TranscodingLogger_tests
+adb shell /data/nativetest/TranscodingLogger_tests/TranscodingLogger_tests
diff --git a/media/libmediatranscoding/transcoder/MediaSampleWriter.cpp b/media/libmediatranscoding/transcoder/MediaSampleWriter.cpp
index 0efe85d..88c1c42 100644
--- a/media/libmediatranscoding/transcoder/MediaSampleWriter.cpp
+++ b/media/libmediatranscoding/transcoder/MediaSampleWriter.cpp
@@ -237,8 +237,8 @@
}
std::chrono::microseconds updateInterval(mHeartBeatIntervalUs);
- std::chrono::system_clock::time_point nextUpdateTime =
- std::chrono::system_clock::now() + updateInterval;
+ std::chrono::steady_clock::time_point nextUpdateTime =
+ std::chrono::steady_clock::now() + updateInterval;
while (true) {
if (trackEosCount >= mTracks.size()) {
diff --git a/media/libmediatranscoding/transcoder/NdkCommon.cpp b/media/libmediatranscoding/transcoder/NdkCommon.cpp
index d78c038..2d85df7 100644
--- a/media/libmediatranscoding/transcoder/NdkCommon.cpp
+++ b/media/libmediatranscoding/transcoder/NdkCommon.cpp
@@ -90,4 +90,29 @@
DEFINE_SET_DEFAULT_FORMAT_VALUE_FUNC(float, Float);
DEFINE_SET_DEFAULT_FORMAT_VALUE_FUNC(int32_t, Int32);
-} // namespace AMediaFormatUtils
\ No newline at end of file
+// Determines whether a track format describes HDR video content or not. The
+// logic is based on isHdr() in libstagefright/Utils.cpp.
+bool VideoIsHdr(AMediaFormat* format) {
+ // If VUI signals HDR content, this internal flag is set by the extractor.
+ int32_t isHdr;
+ if (AMediaFormat_getInt32(format, "android._is-hdr", &isHdr)) {
+ return isHdr;
+ }
+
+ // If container supplied HDR static info without transfer set, assume HDR.
+ const char* hdrInfo;
+ int32_t transfer;
+ if ((AMediaFormat_getString(format, AMEDIAFORMAT_KEY_HDR_STATIC_INFO, &hdrInfo) ||
+ AMediaFormat_getString(format, "hdr10-plus-info", &hdrInfo)) &&
+ !AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_COLOR_TRANSFER, &transfer)) {
+ return true;
+ }
+
+ // Otherwise, check if an HDR transfer function is set.
+ if (AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_COLOR_TRANSFER, &transfer)) {
+ return transfer == COLOR_TRANSFER_ST2084 || transfer == COLOR_TRANSFER_HLG;
+ }
+
+ return false;
+}
+} // namespace AMediaFormatUtils
diff --git a/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp b/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
index 038afd2..4405180 100644
--- a/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
+++ b/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
@@ -51,32 +51,6 @@
// Default frame rate.
static constexpr int32_t kDefaultFrameRate = 30;
-// Determines whether a track format describes HDR video content or not. The
-// logic is based on isHdr() in libstagefright/Utils.cpp.
-static bool isHdr(AMediaFormat* format) {
- // If VUI signals HDR content, this internal flag is set by the extractor.
- int32_t isHdr;
- if (AMediaFormat_getInt32(format, "android._is-hdr", &isHdr)) {
- return isHdr;
- }
-
- // If container supplied HDR static info without transfer set, assume HDR.
- const char* hdrInfo;
- int32_t transfer;
- if ((AMediaFormat_getString(format, AMEDIAFORMAT_KEY_HDR_STATIC_INFO, &hdrInfo) ||
- AMediaFormat_getString(format, "hdr10-plus-info", &hdrInfo)) &&
- !AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_COLOR_TRANSFER, &transfer)) {
- return true;
- }
-
- // Otherwise, check if an HDR transfer function is set.
- if (AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_COLOR_TRANSFER, &transfer)) {
- return transfer == COLOR_TRANSFER_ST2084 || transfer == COLOR_TRANSFER_HLG;
- }
-
- return false;
-}
-
template <typename T>
void VideoTrackTranscoder::BlockingQueue<T>::push(T const& value, bool front) {
{
@@ -347,7 +321,7 @@
}
// Request decoder to convert HDR content to SDR.
- const bool sourceIsHdr = isHdr(mSourceFormat.get());
+ const bool sourceIsHdr = VideoIsHdr(mSourceFormat.get());
if (sourceIsHdr) {
AMediaFormat_setInt32(decoderFormat.get(),
TBD_AMEDIACODEC_PARAMETER_KEY_COLOR_TRANSFER_REQUEST,
diff --git a/media/libmediatranscoding/transcoder/include/media/NdkCommon.h b/media/libmediatranscoding/transcoder/include/media/NdkCommon.h
index 73d880d..c5547c6 100644
--- a/media/libmediatranscoding/transcoder/include/media/NdkCommon.h
+++ b/media/libmediatranscoding/transcoder/include/media/NdkCommon.h
@@ -90,5 +90,7 @@
bool SetDefaultFormatValueFloat(const char* key, AMediaFormat* format, float value);
bool SetDefaultFormatValueInt32(const char* key, AMediaFormat* format, int32_t value);
+bool VideoIsHdr(AMediaFormat* format);
+
} // namespace AMediaFormatUtils
#endif // ANDROID_MEDIA_TRANSCODING_NDK_COMMON_H
diff --git a/media/libnblog/ReportPerformance.cpp b/media/libnblog/ReportPerformance.cpp
index aa678ba..4c78b01 100644
--- a/media/libnblog/ReportPerformance.cpp
+++ b/media/libnblog/ReportPerformance.cpp
@@ -92,8 +92,8 @@
(*dataJson)["threadNum"] = item.first;
root.append(*dataJson);
}
- Json::StyledWriter writer;
- std::string rootStr = writer.write(root);
+ Json::StreamWriterBuilder factory;
+ std::string rootStr = Json::writeString(factory, root);
write(fd, rootStr.c_str(), rootStr.size());
}
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 489a4bd..930bc0f 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -337,6 +337,8 @@
"android.hardware.cas.native@1.0",
"android.hardware.drm@1.0",
"android.hardware.media.omx@1.0",
+ "media_permission-aidl-cpp",
+ "libaudioclient_aidl_conversion",
],
static_libs: [
@@ -349,6 +351,7 @@
"libogg",
"libwebm",
"libstagefright_id3",
+ "media_permission-aidl-cpp",
],
header_libs:[
@@ -363,6 +366,7 @@
"libhidlmemory",
"libmedia",
"android.hidl.allocator@1.0",
+ "media_permission-aidl-cpp",
],
export_include_dirs: [
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index 4bc861e..89fe56f 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -21,6 +21,8 @@
#define LOG_TAG "AudioSource"
#include <utils/Log.h>
+#include <binder/IPCThreadState.h>
+#include <media/AidlConversion.h>
#include <media/AudioRecord.h>
#include <media/stagefright/AudioSource.h>
#include <media/stagefright/MediaBuffer.h>
@@ -32,6 +34,8 @@
namespace android {
+using android::media::permission::Identity;
+
static void AudioRecordCallbackFunction(int event, void *user, void *info) {
AudioSource *source = (AudioSource *) user;
switch (event) {
@@ -50,74 +54,100 @@
}
AudioSource::AudioSource(
+ const audio_attributes_t *attr, const Identity& identity,
+ uint32_t sampleRate, uint32_t channelCount, uint32_t outSampleRate,
+ audio_port_handle_t selectedDeviceId,
+ audio_microphone_direction_t selectedMicDirection,
+ float selectedMicFieldDimension)
+{
+ set(attr, identity, sampleRate, channelCount, outSampleRate, selectedDeviceId,
+ selectedMicDirection, selectedMicFieldDimension);
+}
+
+AudioSource::AudioSource(
const audio_attributes_t *attr, const String16 &opPackageName,
uint32_t sampleRate, uint32_t channelCount, uint32_t outSampleRate,
uid_t uid, pid_t pid, audio_port_handle_t selectedDeviceId,
audio_microphone_direction_t selectedMicDirection,
float selectedMicFieldDimension)
- : mStarted(false),
- mSampleRate(sampleRate),
- mOutSampleRate(outSampleRate > 0 ? outSampleRate : sampleRate),
- mTrackMaxAmplitude(false),
- mStartTimeUs(0),
- mStopSystemTimeUs(-1),
- mLastFrameTimestampUs(0),
- mMaxAmplitude(0),
- mPrevSampleTimeUs(0),
- mInitialReadTimeUs(0),
- mNumFramesReceived(0),
- mNumFramesSkipped(0),
- mNumFramesLost(0),
- mNumClientOwnedBuffers(0),
- mNoMoreFramesToRead(false) {
- ALOGV("sampleRate: %u, outSampleRate: %u, channelCount: %u",
- sampleRate, outSampleRate, channelCount);
- CHECK(channelCount == 1 || channelCount == 2);
- CHECK(sampleRate > 0);
+{
+ // TODO b/182392769: use identity util
+ Identity identity;
+ identity.packageName = VALUE_OR_FATAL(legacy2aidl_String16_string(opPackageName));
+ identity.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(uid));
+ identity.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(pid));
+ set(attr, identity, sampleRate, channelCount, outSampleRate, selectedDeviceId,
+ selectedMicDirection, selectedMicFieldDimension);
+}
- size_t minFrameCount;
- status_t status = AudioRecord::getMinFrameCount(&minFrameCount,
- sampleRate,
- AUDIO_FORMAT_PCM_16_BIT,
- audio_channel_in_mask_from_count(channelCount));
- if (status == OK) {
- // make sure that the AudioRecord callback never returns more than the maximum
- // buffer size
- uint32_t frameCount = kMaxBufferSize / sizeof(int16_t) / channelCount;
+void AudioSource::set(
+ const audio_attributes_t *attr, const Identity& identity,
+ uint32_t sampleRate, uint32_t channelCount, uint32_t outSampleRate,
+ audio_port_handle_t selectedDeviceId,
+ audio_microphone_direction_t selectedMicDirection,
+ float selectedMicFieldDimension)
+{
+ mStarted = false;
+ mSampleRate = sampleRate;
+ mOutSampleRate = outSampleRate > 0 ? outSampleRate : sampleRate;
+ mTrackMaxAmplitude = false;
+ mStartTimeUs = 0;
+ mStopSystemTimeUs = -1;
+ mLastFrameTimestampUs = 0;
+ mMaxAmplitude = 0;
+ mPrevSampleTimeUs = 0;
+ mInitialReadTimeUs = 0;
+ mNumFramesReceived = 0;
+ mNumFramesSkipped = 0;
+ mNumFramesLost = 0;
+ mNumClientOwnedBuffers = 0;
+ mNoMoreFramesToRead = false;
+ ALOGV("sampleRate: %u, outSampleRate: %u, channelCount: %u",
+ sampleRate, outSampleRate, channelCount);
+ CHECK(channelCount == 1 || channelCount == 2);
+ CHECK(sampleRate > 0);
- // make sure that the AudioRecord total buffer size is large enough
- size_t bufCount = 2;
- while ((bufCount * frameCount) < minFrameCount) {
- bufCount++;
- }
+ size_t minFrameCount;
+ status_t status = AudioRecord::getMinFrameCount(&minFrameCount,
+ sampleRate,
+ AUDIO_FORMAT_PCM_16_BIT,
+ audio_channel_in_mask_from_count(channelCount));
+ if (status == OK) {
+ // make sure that the AudioRecord callback never returns more than the maximum
+ // buffer size
+ uint32_t frameCount = kMaxBufferSize / sizeof(int16_t) / channelCount;
- mRecord = new AudioRecord(
- AUDIO_SOURCE_DEFAULT, sampleRate, AUDIO_FORMAT_PCM_16_BIT,
- audio_channel_in_mask_from_count(channelCount),
- opPackageName,
- (size_t) (bufCount * frameCount),
- AudioRecordCallbackFunction,
- this,
- frameCount /*notificationFrames*/,
- AUDIO_SESSION_ALLOCATE,
- AudioRecord::TRANSFER_DEFAULT,
- AUDIO_INPUT_FLAG_NONE,
- uid,
- pid,
- attr,
- selectedDeviceId,
- selectedMicDirection,
- selectedMicFieldDimension);
- // Set caller name so it can be logged in destructor.
- // MediaMetricsConstants.h: AMEDIAMETRICS_PROP_CALLERNAME_VALUE_MEDIA
- mRecord->setCallerName("media");
- mInitCheck = mRecord->initCheck();
- if (mInitCheck != OK) {
- mRecord.clear();
- }
- } else {
- mInitCheck = status;
+ // make sure that the AudioRecord total buffer size is large enough
+ size_t bufCount = 2;
+ while ((bufCount * frameCount) < minFrameCount) {
+ bufCount++;
}
+
+ mRecord = new AudioRecord(
+ AUDIO_SOURCE_DEFAULT, sampleRate, AUDIO_FORMAT_PCM_16_BIT,
+ audio_channel_in_mask_from_count(channelCount),
+ identity,
+ (size_t) (bufCount * frameCount),
+ AudioRecordCallbackFunction,
+ this,
+ frameCount /*notificationFrames*/,
+ AUDIO_SESSION_ALLOCATE,
+ AudioRecord::TRANSFER_DEFAULT,
+ AUDIO_INPUT_FLAG_NONE,
+ attr,
+ selectedDeviceId,
+ selectedMicDirection,
+ selectedMicFieldDimension);
+ // Set caller name so it can be logged in destructor.
+ // MediaMetricsConstants.h: AMEDIAMETRICS_PROP_CALLERNAME_VALUE_MEDIA
+ mRecord->setCallerName("media");
+ mInitCheck = mRecord->initCheck();
+ if (mInitCheck != OK) {
+ mRecord.clear();
+ }
+ } else {
+ mInitCheck = status;
+ }
}
AudioSource::~AudioSource() {
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index bcf418a..b1aa7a9 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -658,7 +658,7 @@
mStartTimeUs = 0;
mNumInputBuffers = 0;
mEncoderFormat = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
- mEncoderDataSpace = HAL_DATASPACE_V0_BT709;
+ mEncoderDataSpace = mBufferDataSpace = HAL_DATASPACE_V0_BT709;
if (meta) {
int64_t startTimeUs;
@@ -678,6 +678,7 @@
}
if (meta->findInt32(kKeyColorSpace, &mEncoderDataSpace)) {
ALOGI("Using encoder data space: %#x", mEncoderDataSpace);
+ mBufferDataSpace = mEncoderDataSpace;
}
}
@@ -908,6 +909,11 @@
(*buffer)->setObserver(this);
(*buffer)->add_ref();
(*buffer)->meta_data().setInt64(kKeyTime, frameTime);
+ if (mBufferDataSpace != mEncoderDataSpace) {
+ ALOGD("Data space updated to %x", mBufferDataSpace);
+ (*buffer)->meta_data().setInt32(kKeyColorSpace, mBufferDataSpace);
+ mEncoderDataSpace = mBufferDataSpace;
+ }
}
return OK;
}
@@ -1039,6 +1045,7 @@
// Find a available memory slot to store the buffer as VideoNativeMetadata.
sp<IMemory> data = *mMemoryBases.begin();
mMemoryBases.erase(mMemoryBases.begin());
+ mBufferDataSpace = buffer.mDataSpace;
ssize_t offset;
size_t size;
diff --git a/media/libstagefright/FrameDecoder.cpp b/media/libstagefright/FrameDecoder.cpp
index a78e6d2..01190b5 100644
--- a/media/libstagefright/FrameDecoder.cpp
+++ b/media/libstagefright/FrameDecoder.cpp
@@ -644,6 +644,10 @@
0,
dstBpp(),
mCaptureLayer != nullptr /*allocRotated*/);
+ if (frameMem == nullptr) {
+ return NO_MEMORY;
+ }
+
mFrame = static_cast<VideoFrame*>(frameMem->unsecurePointer());
setFrame(frameMem);
@@ -886,6 +890,11 @@
if (mFrame == NULL) {
sp<IMemory> frameMem = allocVideoFrame(
trackMeta(), mWidth, mHeight, mTileWidth, mTileHeight, dstBpp());
+
+ if (frameMem == nullptr) {
+ return NO_MEMORY;
+ }
+
mFrame = static_cast<VideoFrame*>(frameMem->unsecurePointer());
setFrame(frameMem);
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 447d599..76a5cab 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -4260,13 +4260,20 @@
void MPEG4Writer::Track::writeColrBox() {
ColorAspects aspects;
memset(&aspects, 0, sizeof(aspects));
+ // Color metadata may have changed.
+ sp<MetaData> meta = mSource->getFormat();
// TRICKY: using | instead of || because we want to execute all findInt32-s
- if (mMeta->findInt32(kKeyColorPrimaries, (int32_t*)&aspects.mPrimaries)
- | mMeta->findInt32(kKeyTransferFunction, (int32_t*)&aspects.mTransfer)
- | mMeta->findInt32(kKeyColorMatrix, (int32_t*)&aspects.mMatrixCoeffs)
- | mMeta->findInt32(kKeyColorRange, (int32_t*)&aspects.mRange)) {
+ if (meta->findInt32(kKeyColorPrimaries, (int32_t*)&aspects.mPrimaries)
+ | meta->findInt32(kKeyTransferFunction, (int32_t*)&aspects.mTransfer)
+ | meta->findInt32(kKeyColorMatrix, (int32_t*)&aspects.mMatrixCoeffs)
+ | meta->findInt32(kKeyColorRange, (int32_t*)&aspects.mRange)) {
int32_t primaries, transfer, coeffs;
bool fullRange;
+ ALOGV("primaries=%s transfer=%s matrix=%s range=%s",
+ asString(aspects.mPrimaries),
+ asString(aspects.mTransfer),
+ asString(aspects.mMatrixCoeffs),
+ asString(aspects.mRange));
ColorUtils::convertCodecColorAspectsToIsoAspects(
aspects, &primaries, &transfer, &coeffs, &fullRange);
mOwner->beginBox("colr");
@@ -4276,6 +4283,8 @@
mOwner->writeInt16(coeffs);
mOwner->writeInt8(int8_t(fullRange ? 0x80 : 0x0));
mOwner->endBox(); // colr
+ } else {
+ ALOGV("no color information");
}
}
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 3e5f9ea..f80b22f 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -118,6 +118,11 @@
static const char *kCodecNumLowLatencyModeOn = "android.media.mediacodec.low-latency.on"; /* 0..n */
static const char *kCodecNumLowLatencyModeOff = "android.media.mediacodec.low-latency.off"; /* 0..n */
static const char *kCodecFirstFrameIndexLowLatencyModeOn = "android.media.mediacodec.low-latency.first-frame"; /* 0..n */
+static const char *kCodecChannelCount = "android.media.mediacodec.channelCount";
+static const char *kCodecSampleRate = "android.media.mediacodec.sampleRate";
+static const char *kCodecVideoEncodedBytes = "android.media.mediacodec.vencode.bytes";
+static const char *kCodecVideoEncodedFrames = "android.media.mediacodec.vencode.frames";
+static const char *kCodecVideoEncodedDurationUs = "android.media.mediacodec.vencode.durationUs";
// the kCodecRecent* fields appear only in getMetrics() results
static const char *kCodecRecentLatencyMax = "android.media.mediacodec.recent.max"; /* in us */
@@ -695,6 +700,10 @@
mHavePendingInputBuffers(false),
mCpuBoostRequested(false),
mLatencyUnknown(0),
+ mBytesEncoded(0),
+ mEarliestEncodedPtsUs(INT64_MAX),
+ mLatestEncodedPtsUs(INT64_MIN),
+ mFramesEncoded(0),
mNumLowLatencyEnables(0),
mNumLowLatencyDisables(0),
mIsLowLatencyModeOn(false),
@@ -802,6 +811,18 @@
mediametrics_setInt64(mMetricsHandle, kCodecLifetimeMs, lifetime);
}
+ if (mBytesEncoded) {
+ Mutex::Autolock al(mOutputStatsLock);
+
+ mediametrics_setInt64(mMetricsHandle, kCodecVideoEncodedBytes, mBytesEncoded);
+ int64_t duration = 0;
+ if (mLatestEncodedPtsUs > mEarliestEncodedPtsUs) {
+ duration = mLatestEncodedPtsUs - mEarliestEncodedPtsUs;
+ }
+ mediametrics_setInt64(mMetricsHandle, kCodecVideoEncodedDurationUs, duration);
+ mediametrics_setInt64(mMetricsHandle, kCodecVideoEncodedFrames, mFramesEncoded);
+ }
+
{
Mutex::Autolock al(mLatencyLock);
mediametrics_setInt64(mMetricsHandle, kCodecNumLowLatencyModeOn, mNumLowLatencyEnables);
@@ -1005,10 +1026,34 @@
}
// when we get a buffer back from the codec
-void MediaCodec::statsBufferReceived(int64_t presentationUs) {
+void MediaCodec::statsBufferReceived(int64_t presentationUs, const sp<MediaCodecBuffer> &buffer) {
CHECK_NE(mState, UNINITIALIZED);
+ if (mIsVideo && (mFlags & kFlagIsEncoder)) {
+ int32_t flags = 0;
+ (void) buffer->meta()->findInt32("flags", &flags);
+
+ // some of these frames, we don't want to count
+ // standalone EOS.... has an invalid timestamp
+ if ((flags & (BUFFER_FLAG_CODECCONFIG|BUFFER_FLAG_EOS)) == 0) {
+ mBytesEncoded += buffer->size();
+ mFramesEncoded++;
+
+ Mutex::Autolock al(mOutputStatsLock);
+ int64_t timeUs = 0;
+ if (buffer->meta()->findInt64("timeUs", &timeUs)) {
+ if (timeUs > mLatestEncodedPtsUs) {
+ mLatestEncodedPtsUs = timeUs;
+ }
+ // can't chain as an else-if or this never triggers
+ if (timeUs < mEarliestEncodedPtsUs) {
+ mEarliestEncodedPtsUs = timeUs;
+ }
+ }
+ }
+ }
+
// mutex access to mBuffersInFlight and other stats
Mutex::Autolock al(mLatencyLock);
@@ -1064,7 +1109,7 @@
return;
}
- // nowNs start our calculations
+ // now start our calculations
const int64_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC);
int64_t latencyUs = (nowNs - startdata.startedNs + 500) / 1000;
@@ -1337,6 +1382,17 @@
ALOGE("Invalid size(s), width=%d, height=%d", mVideoWidth, mVideoHeight);
return BAD_VALUE;
}
+ } else {
+ if (mMetricsHandle != 0) {
+ int32_t channelCount;
+ if (format->findInt32(KEY_CHANNEL_COUNT, &channelCount)) {
+ mediametrics_setInt32(mMetricsHandle, kCodecChannelCount, channelCount);
+ }
+ int32_t sampleRate;
+ if (format->findInt32(KEY_SAMPLE_RATE, &sampleRate)) {
+ mediametrics_setInt32(mMetricsHandle, kCodecSampleRate, sampleRate);
+ }
+ }
}
updateLowLatency(format);
@@ -2183,14 +2239,15 @@
int64_t timeUs;
CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
- statsBufferReceived(timeUs);
-
response->setInt64("timeUs", timeUs);
int32_t flags;
CHECK(buffer->meta()->findInt32("flags", &flags));
response->setInt32("flags", flags);
+
+ statsBufferReceived(timeUs, buffer);
+
response->postReply(replyID);
}
@@ -2281,6 +2338,8 @@
}
postPendingRepliesAndDeferredMessages(origin + ":dead");
sendErrorResponse = false;
+ } else if (!mReplyID) {
+ sendErrorResponse = false;
}
break;
}
@@ -4337,13 +4396,13 @@
msg->setInt64("timeUs", timeUs);
- statsBufferReceived(timeUs);
-
int32_t flags;
CHECK(buffer->meta()->findInt32("flags", &flags));
msg->setInt32("flags", flags);
+ statsBufferReceived(timeUs, buffer);
+
msg->post();
}
}
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index bc656a2..0f7df24 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -30,6 +30,7 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/ColorUtils.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaCodec.h>
#include <media/stagefright/MediaCodecConstants.h>
@@ -768,6 +769,26 @@
memcpy(inbuf->data(), mbuf->data(), size);
if (mIsVideo) {
+ int32_t ds = 0;
+ if (mbuf->meta_data().findInt32(kKeyColorSpace, &ds)
+ && ds != HAL_DATASPACE_UNKNOWN) {
+ android_dataspace dataspace = static_cast<android_dataspace>(ds);
+ ColorUtils::convertDataSpaceToV0(dataspace);
+ ALOGD("Updating dataspace to %x", dataspace);
+ int32_t standard = (int32_t(dataspace) & HAL_DATASPACE_STANDARD_MASK)
+ >> HAL_DATASPACE_STANDARD_SHIFT;
+ int32_t transfer = (int32_t(dataspace) & HAL_DATASPACE_TRANSFER_MASK)
+ >> HAL_DATASPACE_TRANSFER_SHIFT;
+ int32_t range = (int32_t(dataspace) & HAL_DATASPACE_RANGE_MASK)
+ >> HAL_DATASPACE_RANGE_SHIFT;
+ sp<AMessage> msg = new AMessage;
+ msg->setInt32(KEY_COLOR_STANDARD, standard);
+ msg->setInt32(KEY_COLOR_TRANSFER, transfer);
+ msg->setInt32(KEY_COLOR_RANGE, range);
+ msg->setInt32("android._dataspace", dataspace);
+ mEncoder->setParameters(msg);
+ }
+
// video encoder will release MediaBuffer when done
// with underlying data.
inbuf->meta()->setObject("mediaBufferHolder", new MediaBufferHolder(mbuf));
diff --git a/media/libstagefright/MediaExtractorFactory.cpp b/media/libstagefright/MediaExtractorFactory.cpp
index 7c981b3..d77845f 100644
--- a/media/libstagefright/MediaExtractorFactory.cpp
+++ b/media/libstagefright/MediaExtractorFactory.cpp
@@ -188,11 +188,11 @@
// sanity check check struct version, uuid, name
if (plugin->def.def_version != EXTRACTORDEF_VERSION_NDK_V1 &&
plugin->def.def_version != EXTRACTORDEF_VERSION_NDK_V2) {
- ALOGE("don't understand extractor format %u, ignoring.", plugin->def.def_version);
+ ALOGW("don't understand extractor format %u, ignoring.", plugin->def.def_version);
return;
}
if (memcmp(&plugin->def.extractor_uuid, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) == 0) {
- ALOGE("invalid UUID, ignoring");
+ ALOGW("invalid UUID, ignoring");
return;
}
if (plugin->def.extractor_name == NULL || strlen(plugin->def.extractor_name) == 0) {
@@ -244,13 +244,17 @@
void *libHandle = android_dlopen_ext(
libPath.string(),
RTLD_NOW | RTLD_LOCAL, dlextinfo);
- CHECK(libHandle != nullptr)
- << "couldn't dlopen(" << libPath.string() << ") " << strerror(errno);
+ if (libHandle == nullptr) {
+ ALOGI("dlopen(%s) reported error %s", libPath.string(), strerror(errno));
+ continue;
+ }
GetExtractorDef getDef =
(GetExtractorDef) dlsym(libHandle, "GETEXTRACTORDEF");
- CHECK(getDef != nullptr)
- << libPath.string() << " does not contain sniffer";
+ if (getDef == nullptr) {
+ ALOGI("no sniffer found in %s", libPath.string());
+ continue;
+ }
ALOGV("registering sniffer for %s", libPath.string());
RegisterExtractor(
@@ -258,7 +262,7 @@
}
closedir(libDir);
} else {
- ALOGE("couldn't opendir(%s)", libDirPath);
+ ALOGI("plugin directory not present (%s)", libDirPath);
}
}
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index f63740e..51d9730 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -1675,7 +1675,7 @@
if (msg->findString("mime", &mime)) {
meta->setCString(kKeyMIMEType, mime.c_str());
} else {
- ALOGE("did not find mime type");
+ ALOGI("did not find mime type");
return BAD_VALUE;
}
@@ -1725,7 +1725,7 @@
meta->setInt32(kKeyWidth, width);
meta->setInt32(kKeyHeight, height);
} else {
- ALOGE("did not find width and/or height");
+ ALOGI("did not find width and/or height");
return BAD_VALUE;
}
@@ -1814,7 +1814,7 @@
int32_t numChannels, sampleRate;
if (!msg->findInt32("channel-count", &numChannels) ||
!msg->findInt32("sample-rate", &sampleRate)) {
- ALOGE("did not find channel-count and/or sample-rate");
+ ALOGI("did not find channel-count and/or sample-rate");
return BAD_VALUE;
}
meta->setInt32(kKeyChannelCount, numChannels);
diff --git a/media/libstagefright/flac/dec/Android.bp b/media/libstagefright/flac/dec/Android.bp
index 225c930..665aae1 100644
--- a/media/libstagefright/flac/dec/Android.bp
+++ b/media/libstagefright/flac/dec/Android.bp
@@ -40,12 +40,12 @@
},
shared_libs: [
- "libaudioutils",
"liblog",
],
static_libs: [
"libFLAC",
+ "libaudioutils", // needed for 'float_from_i32'
],
export_static_lib_headers: [
diff --git a/media/libstagefright/foundation/AMessage.cpp b/media/libstagefright/foundation/AMessage.cpp
index f242b19..6bb7b37 100644
--- a/media/libstagefright/foundation/AMessage.cpp
+++ b/media/libstagefright/foundation/AMessage.cpp
@@ -1078,6 +1078,17 @@
return OK;
}
+status_t AMessage::removeEntryByName(const char *name) {
+ if (name == nullptr) {
+ return BAD_VALUE;
+ }
+ size_t index = findEntryByName(name);
+ if (index >= mNumItems) {
+ return BAD_INDEX;
+ }
+ return removeEntryAt(index);
+}
+
void AMessage::setItem(const char *name, const ItemData &item) {
if (item.used()) {
Item *it = allocateItem(name);
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/AMessage.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AMessage.h
index 31e58ba..98d6147 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/AMessage.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/AMessage.h
@@ -261,6 +261,17 @@
*/
status_t removeEntryAt(size_t index);
+ /**
+ * Removes an entry based on name.
+ *
+ * \param name name of the entry
+ *
+ * \retval OK the entry was removed successfully
+ * \retval BAD_VALUE name is invalid (null)
+ * \retval BAD_INDEX name not found
+ */
+ status_t removeEntryByName(const char *name);
+
protected:
virtual ~AMessage();
diff --git a/media/libstagefright/foundation/tests/AMessage_test.cpp b/media/libstagefright/foundation/tests/AMessage_test.cpp
new file mode 100644
index 0000000..2b11326
--- /dev/null
+++ b/media/libstagefright/foundation/tests/AMessage_test.cpp
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "AData_test"
+
+#include <gtest/gtest.h>
+#include <utils/RefBase.h>
+
+#include <media/stagefright/foundation/AMessage.h>
+
+using namespace android;
+
+class AMessageTest : public ::testing::Test {
+};
+
+
+TEST(AMessage_tests, item_manipulation) {
+ sp<AMessage> m1 = new AMessage();
+
+ m1->setInt32("value", 2);
+ m1->setInt32("bar", 3);
+
+ int32_t i32;
+ EXPECT_TRUE(m1->findInt32("value", &i32));
+ EXPECT_EQ(2, i32);
+
+ EXPECT_TRUE(m1->findInt32("bar", &i32));
+ EXPECT_EQ(3, i32);
+
+
+ m1->setInt64("big", INT64_MAX);
+ m1->setInt64("smaller", INT64_MAX - 2);
+ m1->setInt64("smallest", 257);
+
+ int64_t i64;
+ EXPECT_TRUE(m1->findInt64("big", &i64));
+ EXPECT_EQ(INT64_MAX, i64);
+
+ EXPECT_TRUE(m1->findInt64("smaller", &i64));
+ EXPECT_EQ(INT64_MAX - 2, i64);
+
+ m1->setSize("size1", 257);
+ m1->setSize("size2", 1023);
+
+ size_t sizing;
+ EXPECT_TRUE(m1->findSize("size2", &sizing));
+ EXPECT_EQ(1023, sizing);
+ EXPECT_TRUE(m1->findSize("size1", &sizing));
+ EXPECT_EQ(257, sizing);
+
+ m1->setDouble("precise", 10.5);
+ m1->setDouble("small", 0.125);
+
+ double d;
+ EXPECT_TRUE(m1->findDouble("precise", &d));
+ EXPECT_EQ(10.5, d);
+
+ EXPECT_TRUE(m1->findDouble("small", &d));
+ EXPECT_EQ(0.125, d);
+
+ // should be unchanged from the top of the test
+ EXPECT_TRUE(m1->findInt32("bar", &i32));
+ EXPECT_EQ(3, i32);
+
+ EXPECT_FALSE(m1->findInt32("nonesuch", &i32));
+ EXPECT_FALSE(m1->findInt64("nonesuch2", &i64));
+ // types disagree, not found
+ EXPECT_FALSE(m1->findInt32("big", &i32));
+ EXPECT_FALSE(m1->findInt32("precise", &i32));
+
+ // integral types should come back true
+ EXPECT_TRUE(m1->findAsInt64("big", &i64));
+ EXPECT_EQ(INT64_MAX, i64);
+ EXPECT_TRUE(m1->findAsInt64("bar", &i64));
+ EXPECT_EQ(3, i64);
+ EXPECT_FALSE(m1->findAsInt64("precise", &i64));
+
+ // recovers ints, size, and floating point values
+ float value;
+ EXPECT_TRUE(m1->findAsFloat("value", &value));
+ EXPECT_EQ(2, value);
+ EXPECT_TRUE(m1->findAsFloat("smallest", &value));
+ EXPECT_EQ(257, value);
+ EXPECT_TRUE(m1->findAsFloat("size2", &value));
+ EXPECT_EQ(1023, value);
+ EXPECT_TRUE(m1->findAsFloat("precise", &value));
+ EXPECT_EQ(10.5, value);
+ EXPECT_TRUE(m1->findAsFloat("small", &value));
+ EXPECT_EQ(0.125, value);
+
+
+ // need to handle still:
+ // strings
+ // Object
+ // Buffer
+ // Message (nested)
+ //
+
+ // removal
+ m1->setInt32("shortlived", 2);
+ m1->setInt32("alittlelonger", 2);
+ EXPECT_EQ(OK, m1->removeEntryByName("shortlived"));
+ EXPECT_EQ(BAD_VALUE, m1->removeEntryByName(nullptr));
+ EXPECT_EQ(BAD_INDEX, m1->removeEntryByName("themythicalnonesuch"));
+ EXPECT_FALSE(m1->findInt32("shortlived", &i32));
+ EXPECT_TRUE(m1->findInt32("alittlelonger", &i32));
+
+ EXPECT_NE(OK, m1->removeEntryByName("notpresent"));
+
+}
+
diff --git a/media/libstagefright/foundation/tests/Android.bp b/media/libstagefright/foundation/tests/Android.bp
index 715b57a..e50742e 100644
--- a/media/libstagefright/foundation/tests/Android.bp
+++ b/media/libstagefright/foundation/tests/Android.bp
@@ -30,6 +30,7 @@
srcs: [
"AData_test.cpp",
+ "AMessage_test.cpp",
"Base64_test.cpp",
"Flagged_test.cpp",
"TypeTraits_test.cpp",
diff --git a/media/libstagefright/include/media/stagefright/AudioSource.h b/media/libstagefright/include/media/stagefright/AudioSource.h
index 451aa57..d1dcdb5 100644
--- a/media/libstagefright/include/media/stagefright/AudioSource.h
+++ b/media/libstagefright/include/media/stagefright/AudioSource.h
@@ -37,16 +37,27 @@
// Note that the "channels" parameter _is_ the number of channels,
// _not_ a bitmask of audio_channels_t constants.
AudioSource(
- const audio_attributes_t *attr,
- const String16 &opPackageName,
- uint32_t sampleRate,
- uint32_t channels,
- uint32_t outSampleRate = 0,
- uid_t uid = -1,
- pid_t pid = -1,
- audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE,
- audio_microphone_direction_t selectedMicDirection = MIC_DIRECTION_UNSPECIFIED,
- float selectedMicFieldDimension = MIC_FIELD_DIMENSION_NORMAL);
+ const audio_attributes_t *attr,
+ const media::permission::Identity& identity,
+ uint32_t sampleRate,
+ uint32_t channels,
+ uint32_t outSampleRate = 0,
+ audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE,
+ audio_microphone_direction_t selectedMicDirection = MIC_DIRECTION_UNSPECIFIED,
+ float selectedMicFieldDimension = MIC_FIELD_DIMENSION_NORMAL);
+
+ // Legacy constructor kept for vendor dependencies
+ AudioSource(
+ const audio_attributes_t *attr,
+ const String16 &opPackageName,
+ uint32_t sampleRate,
+ uint32_t channels,
+ uint32_t outSampleRate = 0,
+ uid_t uid = -1,
+ pid_t pid = -1,
+ audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE,
+ audio_microphone_direction_t selectedMicDirection = MIC_DIRECTION_UNSPECIFIED,
+ float selectedMicFieldDimension = MIC_FIELD_DIMENSION_NORMAL);
status_t initCheck() const;
@@ -131,6 +142,16 @@
AudioSource(const AudioSource &);
AudioSource &operator=(const AudioSource &);
+
+ void set(
+ const audio_attributes_t *attr,
+ const media::permission::Identity& identity,
+ uint32_t sampleRate,
+ uint32_t channels,
+ uint32_t outSampleRate = 0,
+ audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE,
+ audio_microphone_direction_t selectedMicDirection = MIC_DIRECTION_UNSPECIFIED,
+ float selectedMicFieldDimension = MIC_FIELD_DIMENSION_NORMAL);
};
} // namespace android
diff --git a/media/libstagefright/include/media/stagefright/CameraSource.h b/media/libstagefright/include/media/stagefright/CameraSource.h
index 16e7d89..e8770ed 100644
--- a/media/libstagefright/include/media/stagefright/CameraSource.h
+++ b/media/libstagefright/include/media/stagefright/CameraSource.h
@@ -159,6 +159,7 @@
int32_t mColorFormat;
int32_t mEncoderFormat;
int32_t mEncoderDataSpace;
+ int32_t mBufferDataSpace;
status_t mInitCheck;
sp<Camera> mCamera;
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index a28d479..5f64686 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -528,6 +528,14 @@
std::deque<BufferFlightTiming_t> mBuffersInFlight;
Mutex mLatencyLock;
int64_t mLatencyUnknown; // buffers for which we couldn't calculate latency
+
+ Mutex mOutputStatsLock;
+ int64_t mBytesEncoded = 0;
+ int64_t mEarliestEncodedPtsUs = INT64_MAX;
+ int64_t mLatestEncodedPtsUs = INT64_MIN;
+ int32_t mFramesEncoded = 0;
+
+
int64_t mNumLowLatencyEnables; // how many times low latency mode is enabled
int64_t mNumLowLatencyDisables; // how many times low latency mode is disabled
bool mIsLowLatencyModeOn; // is low latency mode on currently
@@ -544,7 +552,7 @@
sp<BatteryChecker> mBatteryChecker;
void statsBufferSent(int64_t presentationUs);
- void statsBufferReceived(int64_t presentationUs);
+ void statsBufferReceived(int64_t presentationUs, const sp<MediaCodecBuffer> &buffer);
enum {
// the default shape of our latency histogram buckets
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
index 619cb44..8fb4db2 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
@@ -794,7 +794,7 @@
constexpr char KEY_PCM_ENCODING[] = "pcm-encoding";
constexpr char KEY_PIXEL_ASPECT_RATIO_HEIGHT[] = "sar-height";
constexpr char KEY_PIXEL_ASPECT_RATIO_WIDTH[] = "sar-width";
-constexpr char KEY_PREPEND_HEADERS_TO_SYNC_FRAMES[] = "prepend-sps-pps-to-idr-frames";
+constexpr char KEY_PREPEND_HEADER_TO_SYNC_FRAMES[] = "prepend-sps-pps-to-idr-frames";
constexpr char KEY_PRIORITY[] = "priority";
constexpr char KEY_PROFILE[] = "profile";
constexpr char KEY_PUSH_BLANK_BUFFERS_ON_STOP[] = "push-blank-buffers-on-shutdown";
diff --git a/media/libstagefright/include/media/stagefright/MediaErrors.h b/media/libstagefright/include/media/stagefright/MediaErrors.h
index cfd5608..d1df2ca 100644
--- a/media/libstagefright/include/media/stagefright/MediaErrors.h
+++ b/media/libstagefright/include/media/stagefright/MediaErrors.h
@@ -94,12 +94,13 @@
ERROR_DRM_PROVISIONING_CERTIFICATE = DRM_ERROR_BASE - 31,
ERROR_DRM_PROVISIONING_CONFIG = DRM_ERROR_BASE - 32,
ERROR_DRM_PROVISIONING_PARSE = DRM_ERROR_BASE - 33,
- ERROR_DRM_PROVISIONING_RETRY = DRM_ERROR_BASE - 34,
- ERROR_DRM_SECURE_STOP_RELEASE = DRM_ERROR_BASE - 35,
- ERROR_DRM_STORAGE_READ = DRM_ERROR_BASE - 36,
- ERROR_DRM_STORAGE_WRITE = DRM_ERROR_BASE - 37,
- ERROR_DRM_ZERO_SUBSAMPLES = DRM_ERROR_BASE - 38,
- ERROR_DRM_LAST_USED_ERRORCODE = DRM_ERROR_BASE - 38,
+ ERROR_DRM_PROVISIONING_REQUEST_REJECTED = DRM_ERROR_BASE - 34,
+ ERROR_DRM_PROVISIONING_RETRY = DRM_ERROR_BASE - 35,
+ ERROR_DRM_SECURE_STOP_RELEASE = DRM_ERROR_BASE - 36,
+ ERROR_DRM_STORAGE_READ = DRM_ERROR_BASE - 37,
+ ERROR_DRM_STORAGE_WRITE = DRM_ERROR_BASE - 38,
+ ERROR_DRM_ZERO_SUBSAMPLES = DRM_ERROR_BASE - 39,
+ ERROR_DRM_LAST_USED_ERRORCODE = ERROR_DRM_ZERO_SUBSAMPLES,
ERROR_DRM_VENDOR_MAX = DRM_ERROR_BASE - 500,
ERROR_DRM_VENDOR_MIN = DRM_ERROR_BASE - 999,
@@ -202,6 +203,7 @@
STATUS_CASE(ERROR_DRM_PROVISIONING_CERTIFICATE);
STATUS_CASE(ERROR_DRM_PROVISIONING_CONFIG);
STATUS_CASE(ERROR_DRM_PROVISIONING_PARSE);
+ STATUS_CASE(ERROR_DRM_PROVISIONING_REQUEST_REJECTED);
STATUS_CASE(ERROR_DRM_PROVISIONING_RETRY);
STATUS_CASE(ERROR_DRM_SECURE_STOP_RELEASE);
STATUS_CASE(ERROR_DRM_STORAGE_READ);
diff --git a/media/libstagefright/tests/fuzzers/Android.bp b/media/libstagefright/tests/fuzzers/Android.bp
index 65e74e6..0097830 100644
--- a/media/libstagefright/tests/fuzzers/Android.bp
+++ b/media/libstagefright/tests/fuzzers/Android.bp
@@ -30,6 +30,7 @@
"libgui",
"libbinder",
"liblog",
+ "media_permission-aidl-cpp",
],
include_dirs: [
"frameworks/av/media/libstagefright",
diff --git a/media/libstagefright/tests/fuzzers/WriterFuzzer.cpp b/media/libstagefright/tests/fuzzers/WriterFuzzer.cpp
index 03e9b43..969c6e1 100644
--- a/media/libstagefright/tests/fuzzers/WriterFuzzer.cpp
+++ b/media/libstagefright/tests/fuzzers/WriterFuzzer.cpp
@@ -17,6 +17,7 @@
// dylan.katz@leviathansecurity.com
#include <android-base/file.h>
+#include <android/media/permission/Identity.h>
#include <ctype.h>
#include <media/mediarecorder.h>
#include <media/stagefright/MPEG4Writer.h>
@@ -39,6 +40,8 @@
namespace android {
+using media::permission::Identity;
+
std::string getFourCC(FuzzedDataProvider *fdp) {
std::string fourCC = fdp->ConsumeRandomLengthString(4);
// Replace any existing nulls
@@ -163,9 +166,11 @@
StandardWriters writerType = dataProvider.ConsumeEnum<StandardWriters>();
sp<MediaWriter> writer = createWriter(tf.fd, writerType, fileMeta);
- std::string packageName = dataProvider.ConsumeRandomLengthString(kMaxPackageNameLen);
-
- sp<MediaRecorder> mr = new MediaRecorder(String16(packageName.c_str()));
+ Identity i;
+ i.packageName = dataProvider.ConsumeRandomLengthString(kMaxPackageNameLen);
+ i.uid = dataProvider.ConsumeIntegral<int32_t>();
+ i.pid = dataProvider.ConsumeIntegral<int32_t>();
+ sp<MediaRecorder> mr = new MediaRecorder(i);
writer->setListener(mr);
uint8_t baseOpLen = operations.size();
diff --git a/media/libstagefright/tests/mediacodec/MediaCodecTest.cpp b/media/libstagefright/tests/mediacodec/MediaCodecTest.cpp
index 6facbd8..06e36ad 100644
--- a/media/libstagefright/tests/mediacodec/MediaCodecTest.cpp
+++ b/media/libstagefright/tests/mediacodec/MediaCodecTest.cpp
@@ -285,10 +285,11 @@
// 1) Client thread calls stop(); MediaCodec looper thread calls
// initiateShutdown(); shutdown is being handled at the component thread.
// 2) Error occurred, but the shutdown operation is still being done.
- // 3) MediaCodec looper thread handles the error.
- // 4) Client releases the codec upon the error; previous shutdown is still
+ // 3) Another error occurred during the shutdown operation.
+ // 4) MediaCodec looper thread handles the error.
+ // 5) Client releases the codec upon the error; previous shutdown is still
// going on.
- // 5) Component thread completes shutdown and posts onStopCompleted();
+ // 6) Component thread completes shutdown and posts onStopCompleted();
// Shutdown from release also completes.
static const AString kCodecName{"test.codec"};
@@ -317,6 +318,9 @@
});
ON_CALL(*mockCodec, initiateShutdown(true))
.WillByDefault([mockCodec](bool) {
+ // 2)
+ mockCodec->callback()->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
+ // 3)
mockCodec->callback()->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
});
ON_CALL(*mockCodec, initiateShutdown(false))
@@ -339,6 +343,8 @@
codec->start();
// stop() will fail because of the error
EXPECT_NE(OK, codec->stop());
+ // sleep here so that the looper thread can handle all the errors.
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
// upon receiving the error, client tries to release the codec.
codec->release();
looper->stop();
diff --git a/media/libstagefright/webm/Android.bp b/media/libstagefright/webm/Android.bp
index 68752cd..3ceacfe 100644
--- a/media/libstagefright/webm/Android.bp
+++ b/media/libstagefright/webm/Android.bp
@@ -40,6 +40,7 @@
"libstagefright_foundation",
"libutils",
"liblog",
+ "media_permission-aidl-cpp",
],
header_libs: [
diff --git a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
index dbdb43c..5a9760d 100644
--- a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
+++ b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
@@ -346,6 +346,7 @@
status_t addAlias(const char **attrs);
status_t addFeature(const char **attrs);
status_t addLimit(const char **attrs);
+ status_t addMapping(const char **attrs);
status_t addQuirk(const char **attrs, const char *prefix = nullptr);
status_t addSetting(const char **attrs, const char *prefix = nullptr);
status_t enterMediaCodec(const char **attrs, bool encoder);
@@ -428,7 +429,7 @@
if (findFileInDirs(searchDirs, fileName, &path)) {
err = parseXmlPath(path);
} else {
- ALOGD("Cannot find %s", path.c_str());
+ ALOGD("Cannot find %s in search path", fileName.c_str());
}
res = combineStatus(res, err);
}
@@ -741,13 +742,16 @@
{
// ignore limits and features specified outside of type
if (!mState->inType()
- && (strEq(name, "Limit") || strEq(name, "Feature") || strEq(name, "Variant"))) {
+ && (strEq(name, "Limit") || strEq(name, "Feature")
+ || strEq(name, "Variant") || strEq(name, "Mapping"))) {
PLOGD("ignoring %s specified outside of a Type", name);
return;
} else if (strEq(name, "Limit")) {
err = addLimit(attrs);
} else if (strEq(name, "Feature")) {
err = addFeature(attrs);
+ } else if (strEq(name, "Mapping")) {
+ err = addMapping(attrs);
} else if (strEq(name, "Variant") && section != SECTION_VARIANT) {
err = limitVariants(attrs);
mState->enterSection(err == OK ? SECTION_VARIANT : SECTION_UNKNOWN);
@@ -981,7 +985,9 @@
TypeMap::iterator typeIt;
if (codecIt == mData->mCodecMap.end()) { // New codec name
if (updating) {
- return { NAME_NOT_FOUND, "MediaCodec: cannot update non-existing codec" };
+ std::string msg = "MediaCodec: cannot update non-existing codec: ";
+ msg = msg + name;
+ return { NAME_NOT_FOUND, msg };
}
// Create a new codec in mCodecMap
codecIt = mData->mCodecMap.insert(Codec(name, CodecProperties())).first;
@@ -994,19 +1000,25 @@
codecIt->second.order = mData->mCodecMap.size();
} else { // Existing codec name
if (!updating) {
- return { ALREADY_EXISTS, "MediaCodec: cannot add existing codec" };
+ std::string msg = "MediaCodec: cannot add existing codec: ";
+ msg = msg + name;
+ return { ALREADY_EXISTS, msg };
}
if (type != nullptr) {
typeIt = codecIt->second.typeMap.find(type);
if (typeIt == codecIt->second.typeMap.end()) {
- return { NAME_NOT_FOUND, "MediaCodec: cannot update non-existing type for codec" };
+ std::string msg = "MediaCodec: cannot update non-existing type for codec: ";
+ msg = msg + name;
+ return { NAME_NOT_FOUND, msg };
}
} else {
// This should happen only when the codec has at most one type.
typeIt = codecIt->second.typeMap.begin();
if (typeIt == codecIt->second.typeMap.end()
|| codecIt->second.typeMap.size() != 1) {
- return { BAD_VALUE, "MediaCodec: cannot update codec without type specified" };
+ std::string msg = "MediaCodec: cannot update codec without type specified: ";
+ msg = msg + name;
+ return { BAD_VALUE, msg };
}
}
}
@@ -1386,6 +1398,53 @@
return OK;
}
+status_t MediaCodecsXmlParser::Impl::Parser::addMapping(const char **attrs) {
+ CHECK(mState->inType());
+ size_t i = 0;
+ const char *a_name = nullptr;
+ const char *a_value = nullptr;
+ const char *a_kind = nullptr;
+
+ while (attrs[i] != nullptr) {
+ CHECK((i & 1) == 0);
+ if (attrs[i + 1] == nullptr) {
+ PLOGD("Mapping: attribute '%s' is null", attrs[i]);
+ return BAD_VALUE;
+ }
+
+ if (strEq(attrs[i], "name")) {
+ a_name = attrs[++i];
+ } else if (strEq(attrs[i], "kind")) {
+ a_kind = attrs[++i];
+ } else if (strEq(attrs[i], "value")) {
+ a_value = attrs[++i];
+ } else {
+ PLOGD("Mapping: ignoring unrecognized attribute '%s'", attrs[i]);
+ ++i;
+ }
+ ++i;
+ }
+
+ // Every mapping must have all 3 fields
+ if (a_name == nullptr) {
+ PLOGD("Mapping with no 'name' attribute");
+ return BAD_VALUE;
+ }
+
+ if (a_kind == nullptr) {
+ PLOGD("Mapping with no 'kind' attribute");
+ return BAD_VALUE;
+ }
+
+ if (a_value == nullptr) {
+ PLOGD("Mapping with no 'value' attribute");
+ return BAD_VALUE;
+ }
+
+ mState->addDetail(std::string("mapping-") + a_kind + "-" + a_name, a_value);
+ return OK;
+}
+
status_t MediaCodecsXmlParser::Impl::Parser::addAlias(const char **attrs) {
CHECK(mState->inCodec());
size_t i = 0;
diff --git a/media/libstagefright/xmlparser/api/current.txt b/media/libstagefright/xmlparser/api/current.txt
index 16c8af8..6f55dc0 100644
--- a/media/libstagefright/xmlparser/api/current.txt
+++ b/media/libstagefright/xmlparser/api/current.txt
@@ -65,6 +65,16 @@
method public void set_default(String);
}
+ public class Mapping {
+ ctor public Mapping();
+ method public String getKind();
+ method public String getName();
+ method public String getValue();
+ method public void setKind(String);
+ method public void setName(String);
+ method public void setValue(String);
+ }
+
public class MediaCodec {
ctor public MediaCodec();
method public java.util.List<media.codecs.Alias> getAlias_optional();
@@ -73,6 +83,7 @@
method public String getEnabled();
method public java.util.List<media.codecs.Feature> getFeature_optional();
method public java.util.List<media.codecs.Limit> getLimit_optional();
+ method public java.util.List<media.codecs.Mapping> getMapping_optional();
method public String getName();
method public java.util.List<media.codecs.Quirk> getQuirk_optional();
method public String getRank();
diff --git a/media/libstagefright/xmlparser/media_codecs.xsd b/media/libstagefright/xmlparser/media_codecs.xsd
index 3b5681f..30974f6 100644
--- a/media/libstagefright/xmlparser/media_codecs.xsd
+++ b/media/libstagefright/xmlparser/media_codecs.xsd
@@ -63,6 +63,7 @@
<xs:element name="Alias" type="Alias" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="Limit" type="Limit" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="Feature" type="Feature" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="Mapping" type="Mapping" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="Variant" type="Variant" minOccurs="0" maxOccurs="unbounded"/>
</xs:choice>
<xs:attribute name="name" type="xs:string"/>
@@ -122,6 +123,11 @@
<xs:attribute name="enabled" type="xs:string"/>
<xs:attribute name="update" type="xs:string"/>
</xs:complexType>
+ <xs:complexType name="Mapping">
+ <xs:attribute name="name" type="xs:string"/>
+ <xs:attribute name="kind" type="xs:string"/>
+ <xs:attribute name="value" type="xs:string"/>
+ </xs:complexType>
<xs:complexType name="Include">
<xs:attribute name="href" type="xs:string"/>
</xs:complexType>
diff --git a/media/libstagefright/xmlparser/test/XMLParserTest.cpp b/media/libstagefright/xmlparser/test/XMLParserTest.cpp
index 9ddd374..c411c8d 100644
--- a/media/libstagefright/xmlparser/test/XMLParserTest.cpp
+++ b/media/libstagefright/xmlparser/test/XMLParserTest.cpp
@@ -127,6 +127,18 @@
setCodecProperties("test8.encoder", true, 8, {}, {}, {}, "audio/opus",
{pair<string, string>("max-limit1", "limit1Max")}, {}, "");
+ setCodecProperties("test9.encoder", true, 9, {}, {}, {}, "video/avc",
+ {
+ pair<string, string>("mapping-sure-before", "after"),
+ },
+ {}, "");
+
+ setCodecProperties("test10.encoder", true, 10, {}, {}, {}, "video/hevc",
+ {
+ pair<string, string>("mapping-fire-from", "to"),
+ },
+ {}, "");
+
setRoleProperties("audio_decoder.mp3", false, 1, "audio/mpeg", "test1.decoder",
{pair<string, string>("attribute::disabled", "present"),
pair<string, string>("rank", "4")});
@@ -162,6 +174,12 @@
setRoleProperties("audio_encoder.opus", true, 8, "audio/opus", "test8.encoder",
{pair<string, string>("max-limit1", "limit1Max")});
+ setRoleProperties("video_encoder.avc", true, 9, "video/avc", "test9.encoder",
+ {pair<string, string>("mapping-sure-before", "after")});
+
+ setRoleProperties("video_encoder.hevc", true, 10, "video/hevc", "test10.encoder",
+ { pair<string, string>("mapping-fire-from", "to")});
+
setServiceAttribute(
{pair<string, string>("domain-telephony", "0"), pair<string, string>("domain-tv", "0"),
pair<string, string>("setting2", "0"), pair<string, string>("variant-variant1", "0")});
diff --git a/media/libstagefright/xmlparser/test/testdata/media_codecs_unit_test.xml b/media/libstagefright/xmlparser/test/testdata/media_codecs_unit_test.xml
index a7299d3..c8913e5 100644
--- a/media/libstagefright/xmlparser/test/testdata/media_codecs_unit_test.xml
+++ b/media/libstagefright/xmlparser/test/testdata/media_codecs_unit_test.xml
@@ -76,5 +76,12 @@
<MediaCodec name="test8.encoder" type="audio/opus">
<Limit name="limit1" max="limit1Max" />
</MediaCodec>
+ <!-- entry for testing Mapping -->
+ <MediaCodec name="test9.encoder" type="video/avc" >
+ <Mapping kind="sure" name="before" value="after"/>
+ </MediaCodec>
+ <MediaCodec name="test10.encoder" type="video/hevc" >
+ <Mapping kind="fire" name="from" value="to"/>
+ </MediaCodec>
</Encoders>
</Included>
diff --git a/media/ndk/TEST_MAPPING b/media/ndk/TEST_MAPPING
index 1a81538..e420812 100644
--- a/media/ndk/TEST_MAPPING
+++ b/media/ndk/TEST_MAPPING
@@ -1,6 +1,7 @@
// mappings for frameworks/av/media/ndk
{
"presubmit": [
- { "name": "AImageReaderWindowHandleTest" }
+ { "name": "AImageReaderWindowHandleTest" },
+ { "name": "libmediandk_test" }
]
}
diff --git a/media/ndk/tests/Android.bp b/media/ndk/tests/Android.bp
new file mode 100644
index 0000000..984b3ee
--- /dev/null
+++ b/media/ndk/tests/Android.bp
@@ -0,0 +1,41 @@
+// Copyright (C) 2016 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.
+
+// Headers module is in frameworks/av/Android.bp because modules are not allowed
+// to refer to headers in parent directories and the headers live in
+// frameworks/av/include.
+
+package {
+ default_applicable_licenses: ["frameworks_av_media_ndk_license"],
+}
+
+cc_test {
+ name: "libmediandk_test",
+ test_suites: ["device-tests"],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+
+ shared_libs: [
+ "liblog",
+ "libmediandk",
+ "libutils",
+ ],
+
+ srcs: [
+ "NdkMediaFormat_test.cpp",
+ ],
+}
diff --git a/media/ndk/tests/NdkMediaFormat_test.cpp b/media/ndk/tests/NdkMediaFormat_test.cpp
new file mode 100644
index 0000000..668d0a4
--- /dev/null
+++ b/media/ndk/tests/NdkMediaFormat_test.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "NdkMediaFormat_test"
+
+#include <gtest/gtest.h>
+#include <utils/RefBase.h>
+
+#include <media/NdkMediaFormat.h>
+
+namespace android {
+
+class NdkMediaFormatTest : public ::testing::Test {
+};
+
+
+TEST(NdkMediaFormat_tests, test_create) {
+
+ AMediaFormat *fmt1 = AMediaFormat_new();
+ AMediaFormat *fmt2 = AMediaFormat_new();
+
+ EXPECT_NE(fmt1, fmt2);
+ EXPECT_NE(fmt1, nullptr);
+ EXPECT_NE(fmt2, nullptr);
+
+ AMediaFormat_delete(fmt1);
+ AMediaFormat_delete(fmt2);
+}
+
+TEST(NdkMediaFormat_tests, test_int32) {
+ AMediaFormat *fmt1 = AMediaFormat_new();
+ int32_t i32;
+ int64_t i64;
+ AMediaFormat_setInt32(fmt1, "five", 5);
+
+ EXPECT_TRUE(AMediaFormat_getInt32(fmt1, "five", &i32));
+ EXPECT_FALSE(AMediaFormat_getInt64(fmt1, "five", &i64));
+ EXPECT_EQ(i32, 5);
+
+ AMediaFormat_delete(fmt1);
+}
+
+TEST(NdkMediaFormat_tests, test_int64) {
+ AMediaFormat *fmt1 = AMediaFormat_new();
+ int64_t i64;
+ AMediaFormat_setInt64(fmt1, "verylarge", INT64_MAX);
+
+ EXPECT_TRUE(AMediaFormat_getInt64(fmt1, "verylarge", &i64));
+ EXPECT_EQ(i64, INT64_MAX);
+
+ // return unchanged if not found
+ i64 = -1;
+ EXPECT_FALSE(AMediaFormat_getInt64(fmt1, "five", &i64));
+ EXPECT_EQ(i64, -1);
+
+ AMediaFormat_delete(fmt1);
+}
+
+TEST(NdkMediaFormat_tests, test_size) {
+ AMediaFormat *fmt1 = AMediaFormat_new();
+
+ size_t size = -15;
+ AMediaFormat_setSize(fmt1, "small", 1);
+ AMediaFormat_setSize(fmt1, "medium", 10);
+ AMediaFormat_setSize(fmt1, "large", 100);
+ EXPECT_TRUE(AMediaFormat_getSize(fmt1, "medium", &size));
+ EXPECT_EQ(size, 10);
+
+ AMediaFormat_delete(fmt1);
+}
+
+TEST(NdkMediaFormat_tests, test_float) {
+ AMediaFormat *fmt1 = AMediaFormat_new();
+ float f;
+ AMediaFormat_setFloat(fmt1, "boat", 1.5);
+ AMediaFormat_setFloat(fmt1, "ship", 0.5);
+ EXPECT_TRUE(AMediaFormat_getFloat(fmt1, "boat", &f));
+ EXPECT_EQ(f, 1.5);
+ AMediaFormat_delete(fmt1);
+}
+
+TEST(NdkMediaFormat_tests, test_double) {
+ AMediaFormat *fmt1 = AMediaFormat_new();
+ double d;
+ AMediaFormat_setDouble(fmt1, "trouble", 100.5);
+ AMediaFormat_setDouble(fmt1, "dip", 0.5);
+ EXPECT_TRUE(AMediaFormat_getDouble(fmt1, "trouble", &d));
+ EXPECT_EQ(d, 100.5);
+ AMediaFormat_delete(fmt1);
+}
+
+TEST(NdkMediaFormat_tests, test_string) {
+ AMediaFormat *fmt1 = AMediaFormat_new();
+
+ const char *content = "This is my test string";
+ const char *out = nullptr;
+ AMediaFormat_setString(fmt1, "stringtheory", content);
+ EXPECT_TRUE(AMediaFormat_getString(fmt1, "stringtheory", &out));
+ EXPECT_NE(out, nullptr);
+ EXPECT_EQ(strcmp(out,content), 0);
+
+ AMediaFormat_delete(fmt1);
+}
+
+
+TEST(NdkMediaFormat_tests, test_clear) {
+ AMediaFormat *fmt1 = AMediaFormat_new();
+
+ int32_t i32;
+ AMediaFormat_setInt32(fmt1, "five", 5);
+ size_t size = -15;
+ AMediaFormat_setSize(fmt1, "medium", 10);
+ float f;
+ AMediaFormat_setFloat(fmt1, "boat", 1.5);
+
+ AMediaFormat_clear(fmt1);
+ EXPECT_FALSE(AMediaFormat_getInt32(fmt1, "five", &i32));
+ EXPECT_FALSE(AMediaFormat_getSize(fmt1, "medium", &size));
+ EXPECT_FALSE(AMediaFormat_getFloat(fmt1, "boat", &f));
+
+ AMediaFormat_delete(fmt1);
+}
+
+TEST(NdkMediaFormat_tests, test_copy) {
+ AMediaFormat *fmt1 = AMediaFormat_new();
+ AMediaFormat *fmt2 = AMediaFormat_new();
+
+ double d;
+ int32_t i32;
+
+ // test copy functionality (NB: we cleared everything just above here)
+ AMediaFormat_setDouble(fmt1, "trouble", 100.5);
+ EXPECT_TRUE(AMediaFormat_getDouble(fmt1, "trouble", &d));
+ EXPECT_FALSE(AMediaFormat_getDouble(fmt2, "trouble", &d));
+
+ EXPECT_EQ(AMEDIA_OK, AMediaFormat_copy(fmt2, fmt1));
+
+ EXPECT_TRUE(AMediaFormat_getDouble(fmt2, "trouble", &d));
+ EXPECT_EQ(d, 100.5);
+
+ AMediaFormat *fmt3 = nullptr;
+ EXPECT_NE(AMEDIA_OK, AMediaFormat_copy(fmt3, fmt1));
+ EXPECT_NE(AMEDIA_OK, AMediaFormat_copy(fmt1, fmt3));
+
+ // we should lose an entry when we copy over it
+ AMediaFormat_setInt32(fmt2, "vanishing", 50);
+ EXPECT_FALSE(AMediaFormat_getInt32(fmt1, "vanishing", &i32));
+ EXPECT_TRUE(AMediaFormat_getInt32(fmt2, "vanishing", &i32));
+ EXPECT_EQ(AMEDIA_OK, AMediaFormat_copy(fmt2, fmt1));
+ EXPECT_FALSE(AMediaFormat_getInt32(fmt2, "vanishing", &i32));
+
+ AMediaFormat_delete(fmt1);
+ AMediaFormat_delete(fmt2);
+}
+
+TEST(NdkMediaFormat_tests, test_buffer) {
+ AMediaFormat *fmt1 = AMediaFormat_new();
+
+ typedef struct blockomem {
+ int leading;
+ int filled[100];
+ int trailing;
+ } block_t;
+ block_t buf = {};
+ buf.leading = 1;
+ buf.trailing = 2;
+ void *data;
+ size_t bsize;
+
+ AMediaFormat_setBuffer(fmt1, "mybuffer", &buf, sizeof(buf));
+ EXPECT_TRUE(AMediaFormat_getBuffer(fmt1, "mybuffer", &data, &bsize));
+ EXPECT_NE(&buf, data);
+ EXPECT_EQ(sizeof(buf), bsize);
+ block_t *bufp = (block_t*) data;
+ EXPECT_EQ(bufp->leading, buf.leading);
+ EXPECT_EQ(bufp->trailing, buf.trailing);
+ EXPECT_EQ(0, memcmp(&buf, data, bsize));
+
+ AMediaFormat_delete(fmt1);
+}
+
+} // namespace android
diff --git a/media/tests/SampleVideoEncoder/README.md b/media/tests/SampleVideoEncoder/README.md
new file mode 100644
index 0000000..074c939
--- /dev/null
+++ b/media/tests/SampleVideoEncoder/README.md
@@ -0,0 +1,42 @@
+# B-Frames Encoding App
+
+This is a sample android application for encoding AVC/HEVC streams with B-Frames enabled. It uses MediaRecorder APIs to record B-frames enabled video from camera2 input and MediaCodec APIs to encode reference test vector using input surface.
+
+This page describes how to get started with the Encoder App.
+
+
+# Getting Started
+
+This app uses the Gradle build system as well as Soong Build System.
+
+To build this project using Gradle build, use the "gradlew build" command or use "Import Project" in Android Studio.
+
+To build the app using Soong Build System, run the following command:
+```
+mmm frameworks/av/media/tests/SampleVideoEncoder/
+```
+
+The apk is generated at the following location:
+```
+out\target\product\sargo\testcases\SampleVideoEncoder\arm64\SampleVideoEncoder.apk
+```
+
+Command to install the apk:
+```
+adb install SampleVideoEncoder.apk
+```
+
+Command to launch the app:
+```
+adb shell am start -n "com.android.media.samplevideoencoder/com.android.media.samplevideoencoder.MainActivity"
+```
+
+After installing the app, a TextureView showing camera preview is dispalyed on one third of the screen. It also features checkboxes to select either avc/hevc and hw/sw codecs. It also has an option to select either MediaRecorder APIs or MediaCodec, along with the 'Start' button to start/stop recording.
+
+
+# Ouput
+
+The muxed ouptput video is saved in the app data at:
+```
+/storage/emulated/0/Android/data/com.android.media.samplevideoencoder/files/
+```
diff --git a/media/tests/SampleVideoEncoder/app/Android.bp b/media/tests/SampleVideoEncoder/app/Android.bp
new file mode 100644
index 0000000..35fe0d8
--- /dev/null
+++ b/media/tests/SampleVideoEncoder/app/Android.bp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+android_app {
+ name: "SampleVideoEncoder",
+
+ manifest: "src/main/AndroidManifest.xml",
+
+ srcs: ["src/**/*.java"],
+
+ sdk_version: "current",
+ min_sdk_version: "24", // N
+
+ resource_dirs: [
+ "src/main/res",
+ ],
+
+ static_libs: [
+ "androidx.annotation_annotation",
+ "androidx.appcompat_appcompat",
+ "androidx-constraintlayout_constraintlayout",
+ ],
+
+ javacflags: [
+ "-Xlint:deprecation",
+ "-Xlint:unchecked",
+ ],
+}
diff --git a/media/tests/SampleVideoEncoder/app/build.gradle b/media/tests/SampleVideoEncoder/app/build.gradle
new file mode 100644
index 0000000..cc54981
--- /dev/null
+++ b/media/tests/SampleVideoEncoder/app/build.gradle
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+apply plugin: 'com.android.application'
+
+android {
+ compileSdkVersion 30
+ buildToolsVersion "30.0.2"
+
+ defaultConfig {
+ applicationId "com.android.media.samplevideoencoder"
+ minSdkVersion 24
+ targetSdkVersion 30
+ versionCode 1
+ versionName "1.0"
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+}
+
+dependencies {
+ implementation fileTree(dir: "libs", include: ["*.jar"])
+ implementation 'androidx.appcompat:appcompat:1.2.0'
+ implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
+ testImplementation 'junit:junit:4.13.1'
+ androidTestImplementation 'androidx.test:runner:1.3.0'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.2'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
+}
\ No newline at end of file
diff --git a/media/tests/SampleVideoEncoder/app/src/main/AndroidManifest.xml b/media/tests/SampleVideoEncoder/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..ed668bb
--- /dev/null
+++ b/media/tests/SampleVideoEncoder/app/src/main/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.media.samplevideoencoder">
+
+ <uses-permission android:name="android.permission.CAMERA"/>
+ <uses-permission android:name="android.permission.RECORD_AUDIO"/>
+
+ <application
+ android:configChanges="orientation"
+ android:screenOrientation="portrait"
+ android:allowBackup="true"
+ android:icon="@mipmap/ic_launcher"
+ android:label="@string/app_name"
+ android:roundIcon="@mipmap/ic_launcher_round"
+ android:supportsRtl="true"
+ android:theme="@style/AppTheme">
+ <activity android:name="com.android.media.samplevideoencoder.MainActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest>
\ No newline at end of file
diff --git a/media/tests/SampleVideoEncoder/app/src/main/java/com/android/media/samplevideoencoder/AutoFitTextureView.java b/media/tests/SampleVideoEncoder/app/src/main/java/com/android/media/samplevideoencoder/AutoFitTextureView.java
new file mode 100644
index 0000000..a3ea4c7
--- /dev/null
+++ b/media/tests/SampleVideoEncoder/app/src/main/java/com/android/media/samplevideoencoder/AutoFitTextureView.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2020 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 com.android.media.samplevideoencoder;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.TextureView;
+
+public class AutoFitTextureView extends TextureView {
+
+ public AutoFitTextureView(Context context) {
+ this(context, null);
+ }
+
+ public AutoFitTextureView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public AutoFitTextureView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ public void setAspectRatio(int width, int height) {
+ if (width < 0 || height < 0) {
+ throw new IllegalArgumentException("Size cannot be negative.");
+ }
+ requestLayout();
+ }
+}
diff --git a/media/tests/SampleVideoEncoder/app/src/main/java/com/android/media/samplevideoencoder/MainActivity.java b/media/tests/SampleVideoEncoder/app/src/main/java/com/android/media/samplevideoencoder/MainActivity.java
new file mode 100644
index 0000000..33e81bb
--- /dev/null
+++ b/media/tests/SampleVideoEncoder/app/src/main/java/com/android/media/samplevideoencoder/MainActivity.java
@@ -0,0 +1,648 @@
+/*
+ * Copyright (C) 2020 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 com.android.media.samplevideoencoder;
+
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.app.ActivityCompat;
+
+import android.Manifest;
+import android.app.Activity;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+
+import android.graphics.Matrix;
+import android.graphics.RectF;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraCaptureSession;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.params.StreamConfigurationMap;
+import android.graphics.SurfaceTexture;
+import android.media.MediaCodecInfo;
+import android.media.MediaFormat;
+import android.media.MediaRecorder;
+
+import android.os.AsyncTask;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.view.Surface;
+import android.view.View;
+import android.view.TextureView;
+import android.widget.Button;
+import android.widget.CheckBox;
+
+import java.io.File;
+import java.io.IOException;
+
+import android.util.Log;
+import android.util.Size;
+import android.widget.RadioGroup;
+import android.widget.Toast;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+import static java.lang.Boolean.FALSE;
+import static java.lang.Boolean.TRUE;
+
+public class MainActivity extends AppCompatActivity
+ implements View.OnClickListener, ActivityCompat.OnRequestPermissionsResultCallback {
+
+ private static final String TAG = "SampleVideoEncoder";
+ private static final String[] RECORD_PERMISSIONS =
+ {Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO};
+ private static final int REQUEST_RECORD_PERMISSIONS = 1;
+ private final Semaphore mCameraOpenCloseLock = new Semaphore(1);
+ private static final int VIDEO_BITRATE = 8000000 /* 8 Mbps */;
+ private static final int VIDEO_FRAMERATE = 30;
+
+ private String mMime = MediaFormat.MIMETYPE_VIDEO_AVC;
+ private String mOutputVideoPath = null;
+
+ private final boolean mIsFrontCamera = true;
+ private boolean mIsCodecSoftware = false;
+ private boolean mIsMediaRecorder = true;
+ private boolean mIsRecording;
+
+ private AutoFitTextureView mTextureView;
+ private CameraDevice mCameraDevice;
+ private CameraCaptureSession mPreviewSession;
+ private CaptureRequest.Builder mPreviewBuilder;
+ private MediaRecorder mMediaRecorder;
+ private Size mVideoSize;
+ private Size mPreviewSize;
+
+ private Handler mBackgroundHandler;
+ private HandlerThread mBackgroundThread;
+
+ private Button mStartButton;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ final RadioGroup radioGroup_mime = findViewById(R.id.radio_group_mime);
+ radioGroup_mime.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(RadioGroup group, int checkedId) {
+ if (checkedId == R.id.avc) {
+ mMime = MediaFormat.MIMETYPE_VIDEO_AVC;
+ } else {
+ mMime = MediaFormat.MIMETYPE_VIDEO_HEVC;
+ }
+ }
+ });
+
+ final RadioGroup radioGroup_codec = findViewById(R.id.radio_group_codec);
+ radioGroup_codec.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(RadioGroup group, int checkedId) {
+ mIsCodecSoftware = checkedId == R.id.sw;
+ }
+ });
+
+ final CheckBox checkBox_mr = findViewById(R.id.checkBox_media_recorder);
+ final CheckBox checkBox_mc = findViewById(R.id.checkBox_media_codec);
+ mTextureView = findViewById(R.id.texture);
+ checkBox_mr.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ boolean checked = ((CheckBox) v).isChecked();
+ if (checked) {
+ checkBox_mc.setChecked(false);
+ mIsMediaRecorder = TRUE;
+ for (int i = 0; i < radioGroup_codec.getChildCount(); i++) {
+ radioGroup_codec.getChildAt(i).setEnabled(false);
+ }
+ }
+ }
+ });
+ checkBox_mc.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ boolean checked = ((CheckBox) v).isChecked();
+ if (checked) {
+ checkBox_mr.setChecked(false);
+ mIsMediaRecorder = FALSE;
+ for (int i = 0; i < radioGroup_codec.getChildCount(); i++) {
+ radioGroup_codec.getChildAt(i).setEnabled(true);
+ }
+ }
+ }
+ });
+ mStartButton = findViewById(R.id.start_button);
+ mStartButton.setOnClickListener(this);
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (v.getId() == R.id.start_button) {
+ if (mIsMediaRecorder) {
+ if (mIsRecording) {
+ stopRecordingVideo();
+ } else {
+ mStartButton.setEnabled(false);
+ startRecordingVideo();
+ }
+ } else {
+ mStartButton.setEnabled(false);
+ mOutputVideoPath = getVideoPath(MainActivity.this);
+ MediaCodecSurfaceAsync codecAsyncTask = new MediaCodecSurfaceAsync(this);
+ codecAsyncTask.execute(
+ "Encoding reference test vector with MediaCodec APIs using surface");
+ }
+ }
+ }
+
+ private static class MediaCodecSurfaceAsync extends AsyncTask<String, String, Integer> {
+
+ private final WeakReference<MainActivity> activityReference;
+
+ MediaCodecSurfaceAsync(MainActivity context) {
+ activityReference = new WeakReference<>(context);
+ }
+
+ @Override
+ protected Integer doInBackground(String... strings) {
+ MainActivity mainActivity = activityReference.get();
+ int resId = R.raw.crowd_1920x1080_25fps_4000kbps_h265;
+ int encodingStatus = 1;
+ MediaCodecSurfaceEncoder codecSurfaceEncoder =
+ new MediaCodecSurfaceEncoder(mainActivity.getApplicationContext(), resId,
+ mainActivity.mMime, mainActivity.mIsCodecSoftware,
+ mainActivity.mOutputVideoPath);
+ try {
+ encodingStatus = codecSurfaceEncoder.startEncodingSurface();
+ } catch (IOException | InterruptedException e) {
+ e.printStackTrace();
+ }
+ return encodingStatus;
+ }
+
+ @Override
+ protected void onPostExecute(Integer encodingStatus) {
+ MainActivity mainActivity = activityReference.get();
+ mainActivity.mStartButton.setEnabled(true);
+ if (encodingStatus == 0) {
+ Toast.makeText(mainActivity.getApplicationContext(), "Encoding Completed",
+ Toast.LENGTH_SHORT).show();
+ } else {
+ Toast.makeText(mainActivity.getApplicationContext(),
+ "Error occurred while " + "encoding", Toast.LENGTH_SHORT).show();
+ }
+ mainActivity.mOutputVideoPath = null;
+ super.onPostExecute(encodingStatus);
+ }
+ }
+
+ private final TextureView.SurfaceTextureListener mSurfaceTextureListener =
+ new TextureView.SurfaceTextureListener() {
+
+ @Override
+ public void onSurfaceTextureAvailable(SurfaceTexture surface, int width,
+ int height) {
+ openCamera(width, height);
+ }
+
+ @Override
+ public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width,
+ int height) {
+ configureTransform(width, height);
+ Log.v(TAG, "Keeping camera preview size fixed");
+ }
+
+ @Override
+ public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
+ return true;
+ }
+
+ @Override
+ public void onSurfaceTextureUpdated(SurfaceTexture surface) {
+ }
+ };
+
+
+ private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
+
+ @Override
+ public void onOpened(CameraDevice cameraDevice) {
+ mCameraDevice = cameraDevice;
+ startPreview();
+ mCameraOpenCloseLock.release();
+ }
+
+ @Override
+ public void onDisconnected(CameraDevice cameraDevice) {
+ mCameraOpenCloseLock.release();
+ cameraDevice.close();
+ mCameraDevice = null;
+ }
+
+ @Override
+ public void onError(CameraDevice cameraDevice, int error) {
+ mCameraOpenCloseLock.release();
+ cameraDevice.close();
+ mCameraDevice = null;
+ Activity activity = MainActivity.this;
+ activity.finish();
+ }
+ };
+
+ private boolean shouldShowRequestPermissionRationale(String[] recordPermissions) {
+ for (String permission : recordPermissions) {
+ if (ActivityCompat.shouldShowRequestPermissionRationale(this, permission)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void requestRecordPermissions() {
+ if (!shouldShowRequestPermissionRationale(RECORD_PERMISSIONS)) {
+ ActivityCompat.requestPermissions(this, RECORD_PERMISSIONS, REQUEST_RECORD_PERMISSIONS);
+ }
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, String[] permissions,
+ int[] grantResults) {
+ if (requestCode == REQUEST_RECORD_PERMISSIONS) {
+ if (grantResults.length == RECORD_PERMISSIONS.length) {
+ for (int result : grantResults) {
+ if (result != PackageManager.PERMISSION_GRANTED) {
+ Log.e(TAG, "Permission is not granted");
+ break;
+ }
+ }
+ }
+ } else {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+ }
+ }
+
+ @SuppressWarnings("MissingPermission")
+ private void openCamera(int width, int height) {
+ if (!hasPermissionGranted(RECORD_PERMISSIONS)) {
+ Log.e(TAG, "Camera does not have permission to record video");
+ requestRecordPermissions();
+ return;
+ }
+ final Activity activity = MainActivity.this;
+ if (activity == null || activity.isFinishing()) {
+ Log.e(TAG, "Activity not found");
+ return;
+ }
+ CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
+ try {
+ Log.v(TAG, "Acquire Camera");
+ if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
+ throw new RuntimeException("Timed out waiting to lock camera opening");
+ }
+ Log.d(TAG, "Camera Acquired");
+
+ String cameraId = manager.getCameraIdList()[0];
+ if (mIsFrontCamera) {
+ cameraId = manager.getCameraIdList()[1];
+ }
+
+ CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
+ StreamConfigurationMap map =
+ characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+ mVideoSize = chooseVideoSize(map.getOutputSizes(MediaRecorder.class));
+ mPreviewSize =
+ chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class), width, height,
+ mVideoSize);
+ mTextureView.setAspectRatio(mPreviewSize.getHeight(), mPreviewSize.getWidth());
+ configureTransform(width, height);
+ mMediaRecorder = new MediaRecorder();
+ manager.openCamera(cameraId, mStateCallback, null);
+ } catch (InterruptedException | CameraAccessException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void closeCamera() {
+ try {
+ mCameraOpenCloseLock.acquire();
+ closePreviewSession();
+ if (null != mCameraDevice) {
+ mCameraDevice.close();
+ mCameraDevice = null;
+ }
+ if (null != mMediaRecorder) {
+ mMediaRecorder.release();
+ mMediaRecorder = null;
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Interrupted while trying to lock camera closing.");
+ } finally {
+ mCameraOpenCloseLock.release();
+ }
+ }
+
+ private static Size chooseVideoSize(Size[] choices) {
+ for (Size size : choices) {
+ if (size.getWidth() == size.getHeight() * 16 / 9 && size.getWidth() <= 1920) {
+ return size;
+ }
+ }
+ Log.e(TAG, "Couldn't find any suitable video size");
+ return choices[choices.length - 1];
+ }
+
+ private static Size chooseOptimalSize(Size[] choices, int width, int height, Size aspectRatio) {
+ List<Size> bigEnough = new ArrayList<>();
+ int w = aspectRatio.getWidth();
+ int h = aspectRatio.getHeight();
+ for (Size option : choices) {
+ if (option.getHeight() == option.getWidth() * h / w && option.getWidth() >= width &&
+ option.getHeight() >= height) {
+ bigEnough.add(option);
+ }
+ }
+
+ // Pick the smallest of those, assuming we found any
+ if (bigEnough.size() > 0) {
+ return Collections.min(bigEnough, new CompareSizesByArea());
+ } else {
+ Log.e(TAG, "Couldn't find any suitable preview size");
+ return choices[0];
+ }
+ }
+
+ private boolean hasPermissionGranted(String[] recordPermissions) {
+ for (String permission : recordPermissions) {
+ if (ActivityCompat.checkSelfPermission(MainActivity.this, permission) !=
+ PackageManager.PERMISSION_GRANTED) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ startBackgroundThread();
+ if (mTextureView.isAvailable()) {
+ openCamera(mTextureView.getWidth(), mTextureView.getHeight());
+ } else {
+ mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
+ }
+ }
+
+ @Override
+ public void onPause() {
+ closeCamera();
+ stopBackgroundThread();
+ super.onPause();
+ }
+
+ private void startBackgroundThread() {
+ mBackgroundThread = new HandlerThread("CameraBackground");
+ mBackgroundThread.start();
+ mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
+ }
+
+ private void stopBackgroundThread() {
+ mBackgroundThread.quitSafely();
+ try {
+ mBackgroundThread.join();
+ mBackgroundThread = null;
+ mBackgroundHandler = null;
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void startRecordingVideo() {
+ if (null == mCameraDevice || !mTextureView.isAvailable() || null == mPreviewSize) {
+ Toast.makeText(MainActivity.this, "Cannot start recording.", Toast.LENGTH_SHORT).show();
+ Log.e(TAG, "Cannot start recording.");
+ return;
+ }
+ try {
+ closePreviewSession();
+ setUpMediaRecorder();
+ SurfaceTexture texture = mTextureView.getSurfaceTexture();
+ assert texture != null;
+ texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
+ mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
+ List<Surface> surfaces = new ArrayList<>();
+
+ // Set up Surface for the camera preview
+ Surface previewSurface = new Surface(texture);
+ surfaces.add(previewSurface);
+ mPreviewBuilder.addTarget(previewSurface);
+
+ // Set up Surface for the MediaRecorder
+ Surface recorderSurface = mMediaRecorder.getSurface();
+ surfaces.add(recorderSurface);
+ mPreviewBuilder.addTarget(recorderSurface);
+
+ //Start a capture session
+ mCameraDevice.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() {
+
+ @Override
+ public void onConfigured(CameraCaptureSession session) {
+ mPreviewSession = session;
+ updatePreview();
+ MainActivity.this.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mIsRecording = true;
+ mMediaRecorder.start();
+ mStartButton.setText(R.string.stop);
+ mStartButton.setEnabled(true);
+ }
+ });
+ }
+
+ @Override
+ public void onConfigureFailed(CameraCaptureSession session) {
+ Log.e(TAG, "Failed to configure. Cannot start Recording");
+ }
+ }, mBackgroundHandler);
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void setUpMediaRecorder() {
+ final Activity activity = MainActivity.this;
+ if (activity == null) {
+ Toast.makeText(MainActivity.this, "Error occurred while setting up the MediaRecorder",
+ Toast.LENGTH_SHORT).show();
+ Log.e(TAG, "Error occurred while setting up the MediaRecorder");
+ return;
+ }
+ try {
+ mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
+ mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
+ mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
+ } catch (IllegalStateException e) {
+ e.printStackTrace();
+ }
+ if (mOutputVideoPath == null) {
+ mOutputVideoPath = getVideoPath(MainActivity.this);
+ }
+ mMediaRecorder.setOutputFile(mOutputVideoPath);
+ mMediaRecorder.setVideoEncodingBitRate(VIDEO_BITRATE);
+ mMediaRecorder.setVideoFrameRate(VIDEO_FRAMERATE);
+ mMediaRecorder.setVideoSize(mVideoSize.getWidth(), mVideoSize.getHeight());
+ mMediaRecorder.setOrientationHint(270);
+ if (mMime.equals(MediaFormat.MIMETYPE_VIDEO_HEVC)) {
+ mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.HEVC);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ mMediaRecorder.setVideoEncodingProfileLevel(
+ MediaCodecInfo.CodecProfileLevel.HEVCProfileMain,
+ MediaCodecInfo.CodecProfileLevel.HEVCMainTierLevel4);
+ }
+ } else {
+ mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ mMediaRecorder.setVideoEncodingProfileLevel(
+ MediaCodecInfo.CodecProfileLevel.AVCProfileMain,
+ MediaCodecInfo.CodecProfileLevel.AVCLevel4);
+ }
+ }
+ mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
+ try {
+ mMediaRecorder.prepare();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private String getVideoPath(Activity activity) {
+ File dir = activity.getApplicationContext().getExternalFilesDir(null);
+ if (dir == null) {
+ Log.e(TAG, "Cannot get external directory path to save output video");
+ return null;
+ }
+ String videoPath = dir.getAbsolutePath() + "/Video-" + System.currentTimeMillis() + ".mp4";
+ Log.d(TAG, "Output video is saved at: " + videoPath);
+ return videoPath;
+ }
+
+ private void closePreviewSession() {
+ if (mPreviewSession != null) {
+ mPreviewSession.close();
+ mPreviewSession = null;
+ }
+ }
+
+ private void stopRecordingVideo() {
+ mIsRecording = false;
+ mStartButton.setText(R.string.start);
+ mMediaRecorder.stop();
+ mMediaRecorder.reset();
+ Toast.makeText(MainActivity.this, "Recording Finished", Toast.LENGTH_SHORT).show();
+ mOutputVideoPath = null;
+ startPreview();
+ }
+
+ private void startPreview() {
+ if (null == mCameraDevice || !mTextureView.isAvailable() || null == mPreviewSize) {
+ return;
+ }
+ try {
+ closePreviewSession();
+ SurfaceTexture texture = mTextureView.getSurfaceTexture();
+ assert texture != null;
+ texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
+ mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
+
+ Surface previewSurface = new Surface(texture);
+ mPreviewBuilder.addTarget(previewSurface);
+
+ mCameraDevice.createCaptureSession(Collections.singletonList(previewSurface),
+ new CameraCaptureSession.StateCallback() {
+
+ @Override
+ public void onConfigured(CameraCaptureSession session) {
+ mPreviewSession = session;
+ updatePreview();
+ }
+
+ @Override
+ public void onConfigureFailed(CameraCaptureSession session) {
+ Toast.makeText(MainActivity.this,
+ "Configure Failed; Cannot start " + "preview",
+ Toast.LENGTH_SHORT).show();
+ Log.e(TAG, "Configure failed; Cannot start preview");
+ }
+ }, mBackgroundHandler);
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void updatePreview() {
+ if (mCameraDevice == null) {
+ Toast.makeText(MainActivity.this, "Camera not found; Cannot update " + "preview",
+ Toast.LENGTH_SHORT).show();
+ Log.e(TAG, "Camera not found; Cannot update preview");
+ return;
+ }
+ try {
+ mPreviewBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
+ HandlerThread thread = new HandlerThread("Camera preview");
+ thread.start();
+ mPreviewSession.setRepeatingRequest(mPreviewBuilder.build(), null, mBackgroundHandler);
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void configureTransform(int viewWidth, int viewHeight) {
+ Activity activity = MainActivity.this;
+ if (null == mTextureView || null == mPreviewSize || null == activity) {
+ return;
+ }
+ Matrix matrix = new Matrix();
+ RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
+ RectF bufferRect = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth());
+ float centerX = viewRect.centerX();
+ float centerY = viewRect.centerY();
+ bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
+ matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
+ float scale = Math.max((float) viewHeight / mPreviewSize.getHeight(),
+ (float) viewWidth / mPreviewSize.getWidth());
+ matrix.postScale(scale, scale, centerX, centerY);
+ mTextureView.setTransform(matrix);
+ }
+
+ static class CompareSizesByArea implements Comparator<Size> {
+ @Override
+ public int compare(Size lhs, Size rhs) {
+ return Long.signum((long) lhs.getWidth() * lhs.getHeight() -
+ (long) rhs.getWidth() * rhs.getHeight());
+ }
+ }
+}
diff --git a/media/tests/SampleVideoEncoder/app/src/main/java/com/android/media/samplevideoencoder/MediaCodecBase.java b/media/tests/SampleVideoEncoder/app/src/main/java/com/android/media/samplevideoencoder/MediaCodecBase.java
new file mode 100644
index 0000000..88ce73b
--- /dev/null
+++ b/media/tests/SampleVideoEncoder/app/src/main/java/com/android/media/samplevideoencoder/MediaCodecBase.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2020 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 com.android.media.samplevideoencoder;
+
+import android.media.MediaCodec;
+import android.media.MediaCodecInfo;
+import android.media.MediaCodecList;
+import android.media.MediaFormat;
+import android.os.Build;
+import android.util.Log;
+import android.util.Pair;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+class CodecAsyncHandler extends MediaCodec.Callback {
+ private static final String TAG = CodecAsyncHandler.class.getSimpleName();
+ private final Lock mLock = new ReentrantLock();
+ private final Condition mCondition = mLock.newCondition();
+ private final LinkedList<Pair<Integer, MediaCodec.BufferInfo>> mCbInputQueue;
+ private final LinkedList<Pair<Integer, MediaCodec.BufferInfo>> mCbOutputQueue;
+ private volatile boolean mSignalledError;
+
+ CodecAsyncHandler() {
+ mCbInputQueue = new LinkedList<>();
+ mCbOutputQueue = new LinkedList<>();
+ mSignalledError = false;
+ }
+
+ void clearQueues() {
+ mLock.lock();
+ mCbInputQueue.clear();
+ mCbOutputQueue.clear();
+ mLock.unlock();
+ }
+
+ void resetContext() {
+ clearQueues();
+ mSignalledError = false;
+ }
+
+ @Override
+ public void onInputBufferAvailable(MediaCodec codec, int bufferIndex) {
+ mLock.lock();
+ mCbInputQueue.add(new Pair<>(bufferIndex, (MediaCodec.BufferInfo) null));
+ mCondition.signalAll();
+ mLock.unlock();
+ }
+
+ @Override
+ public void onOutputBufferAvailable(MediaCodec codec, int bufferIndex,
+ MediaCodec.BufferInfo info) {
+ mLock.lock();
+ mCbOutputQueue.add(new Pair<>(bufferIndex, info));
+ mCondition.signalAll();
+ mLock.unlock();
+ }
+
+ @Override
+ public void onError(MediaCodec codec, MediaCodec.CodecException e) {
+ mLock.lock();
+ mSignalledError = true;
+ mCondition.signalAll();
+ mLock.unlock();
+ Log.e(TAG, "Received media codec error : " + e.getMessage());
+ }
+
+ @Override
+ public void onOutputFormatChanged(MediaCodec codec, MediaFormat format) {
+ Log.i(TAG, "Output format changed: " + format.toString());
+ }
+
+ void setCallBack(MediaCodec codec, boolean isCodecInAsyncMode) {
+ if (isCodecInAsyncMode) {
+ codec.setCallback(this);
+ }
+ }
+
+ Pair<Integer, MediaCodec.BufferInfo> getOutput() throws InterruptedException {
+ Pair<Integer, MediaCodec.BufferInfo> element = null;
+ mLock.lock();
+ while (!mSignalledError) {
+ if (mCbOutputQueue.isEmpty()) {
+ mCondition.await();
+ } else {
+ element = mCbOutputQueue.remove(0);
+ break;
+ }
+ }
+ mLock.unlock();
+ return element;
+ }
+
+ Pair<Integer, MediaCodec.BufferInfo> getWork() throws InterruptedException {
+ Pair<Integer, MediaCodec.BufferInfo> element = null;
+ mLock.lock();
+ while (!mSignalledError) {
+ if (mCbInputQueue.isEmpty() && mCbOutputQueue.isEmpty()) {
+ mCondition.await();
+ } else {
+ if (!mCbOutputQueue.isEmpty()) {
+ element = mCbOutputQueue.remove(0);
+ break;
+ }
+ if (!mCbInputQueue.isEmpty()) {
+ element = mCbInputQueue.remove(0);
+ break;
+ }
+ }
+ }
+ mLock.unlock();
+ return element;
+ }
+
+ boolean hasSeenError() {
+ return mSignalledError;
+ }
+}
+
+abstract public class MediaCodecBase {
+ static ArrayList<String> selectCodecs(String mime, ArrayList<MediaFormat> formats,
+ String[] features, boolean isEncoder,
+ boolean isSoftware) {
+
+ MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+ MediaCodecInfo[] codecInfos = codecList.getCodecInfos();
+ ArrayList<String> listOfCodecs = new ArrayList<>();
+ for (MediaCodecInfo codecInfo : codecInfos) {
+ if (isEncoder) {
+ if (!codecInfo.isEncoder()) continue;
+ } else {
+ if (codecInfo.isEncoder()) continue;
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && codecInfo.isAlias()) continue;
+ String[] types = codecInfo.getSupportedTypes();
+ for (String type : types) {
+ if (type.equalsIgnoreCase(mime)) {
+ boolean isOk = true;
+ MediaCodecInfo.CodecCapabilities codecCapabilities =
+ codecInfo.getCapabilitiesForType(type);
+ if (formats != null) {
+ for (MediaFormat format : formats) {
+ if (!codecCapabilities.isFormatSupported(format)) {
+ isOk = false;
+ break;
+ }
+ }
+ }
+ if (features != null) {
+ for (String feature : features) {
+ if (!codecCapabilities.isFeatureSupported(feature)) {
+ isOk = false;
+ break;
+ }
+ }
+ }
+ if (isSoftware) {
+ if (codecInfo.getName().contains("software") ||
+ codecInfo.getName().contains("android") ||
+ codecInfo.getName().contains("google")) {
+ if (isOk) listOfCodecs.add(codecInfo.getName());
+ }
+ } else {
+ if (codecInfo.getName().contains("software") ||
+ codecInfo.getName().contains("android") ||
+ codecInfo.getName().contains("google")) {
+ continue;
+ } else {
+ if (isOk) listOfCodecs.add(codecInfo.getName());
+ }
+ }
+ }
+ }
+ }
+ return listOfCodecs;
+ }
+}
diff --git a/media/tests/SampleVideoEncoder/app/src/main/java/com/android/media/samplevideoencoder/MediaCodecSurfaceEncoder.java b/media/tests/SampleVideoEncoder/app/src/main/java/com/android/media/samplevideoencoder/MediaCodecSurfaceEncoder.java
new file mode 100644
index 0000000..146a475
--- /dev/null
+++ b/media/tests/SampleVideoEncoder/app/src/main/java/com/android/media/samplevideoencoder/MediaCodecSurfaceEncoder.java
@@ -0,0 +1,356 @@
+/*
+ * Copyright (C) 2020 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 com.android.media.samplevideoencoder;
+
+import android.content.Context;
+import android.content.res.AssetFileDescriptor;
+import android.media.MediaCodec;
+import android.media.MediaCodecInfo;
+import android.media.MediaExtractor;
+import android.media.MediaFormat;
+import android.media.MediaMuxer;
+import android.os.Build;
+import android.util.Log;
+import android.util.Pair;
+import android.view.Surface;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+
+public class MediaCodecSurfaceEncoder {
+ private static final String TAG = MediaCodecSurfaceEncoder.class.getSimpleName();
+
+ private static final boolean DEBUG = false;
+ private static final int VIDEO_BITRATE = 8000000 /*8 Mbps*/;
+ private static final int VIDEO_FRAMERATE = 30;
+ private final Context mActivityContext;
+ private final int mResID;
+ private final int mMaxBFrames;
+ private final String mMime;
+ private final String mOutputPath;
+ private int mTrackID = -1;
+
+ private Surface mSurface;
+ private MediaExtractor mExtractor;
+ private MediaCodec mDecoder;
+ private MediaCodec mEncoder;
+ private MediaMuxer mMuxer;
+
+ private final boolean mIsCodecSoftware;
+ private boolean mSawDecInputEOS;
+ private boolean mSawDecOutputEOS;
+ private boolean mSawEncOutputEOS;
+ private int mDecOutputCount;
+ private int mEncOutputCount;
+
+ private final CodecAsyncHandler mAsyncHandleEncoder = new CodecAsyncHandler();
+ private final CodecAsyncHandler mAsyncHandleDecoder = new CodecAsyncHandler();
+
+ public MediaCodecSurfaceEncoder(Context context, int resId, String mime, boolean isSoftware,
+ String outputPath, int maxBFrames) {
+ mActivityContext = context;
+ mResID = resId;
+ mMime = mime;
+ mIsCodecSoftware = isSoftware;
+ mOutputPath = outputPath;
+ mMaxBFrames = maxBFrames;
+ }
+
+ public MediaCodecSurfaceEncoder(Context context, int resId, String mime, boolean isSoftware,
+ String outputPath) {
+ // Default value of MediaFormat.KEY_MAX_B_FRAMES is set to 1, if not passed as a parameter.
+ this(context, resId, mime, isSoftware, outputPath, 1);
+ }
+
+ public int startEncodingSurface() throws IOException, InterruptedException {
+ MediaFormat decoderFormat = setUpSource();
+ if (decoderFormat == null) {
+ return -1;
+ }
+
+ String decoderMime = decoderFormat.getString(MediaFormat.KEY_MIME);
+ ArrayList<String> listOfDeocders =
+ MediaCodecBase.selectCodecs(decoderMime, null, null, false, mIsCodecSoftware);
+ if (listOfDeocders.isEmpty()) {
+ Log.e(TAG, "No suitable decoder found for mime: " + decoderMime);
+ return -1;
+ }
+ mDecoder = MediaCodec.createByCodecName(listOfDeocders.get(0));
+
+ MediaFormat encoderFormat = setUpEncoderFormat(decoderFormat);
+ ArrayList<String> listOfEncoders =
+ MediaCodecBase.selectCodecs(mMime, null, null, true, mIsCodecSoftware);
+ if (listOfEncoders.isEmpty()) {
+ Log.e(TAG, "No suitable encoder found for mime: " + mMime);
+ return -1;
+ }
+
+ boolean muxOutput = true;
+ for (String encoder : listOfEncoders) {
+ mEncoder = MediaCodec.createByCodecName(encoder);
+ mExtractor.seekTo(0, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
+ if (muxOutput) {
+ int muxerFormat = MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4;
+ mMuxer = new MediaMuxer(mOutputPath, muxerFormat);
+ }
+ configureCodec(decoderFormat, encoderFormat);
+ mEncoder.start();
+ mDecoder.start();
+ doWork(Integer.MAX_VALUE);
+ queueEOS();
+ waitForAllEncoderOutputs();
+ if (muxOutput) {
+ if (mTrackID != -1) {
+ mMuxer.stop();
+ mTrackID = -1;
+ }
+ if (mMuxer != null) {
+ mMuxer.release();
+ mMuxer = null;
+ }
+ }
+ mDecoder.reset();
+ mEncoder.reset();
+ mSurface.release();
+ mSurface = null;
+ }
+
+ mEncoder.release();
+ mDecoder.release();
+ mExtractor.release();
+ return 0;
+ }
+
+ private MediaFormat setUpSource() throws IOException {
+ mExtractor = new MediaExtractor();
+ AssetFileDescriptor fd = mActivityContext.getResources().openRawResourceFd(mResID);
+ mExtractor.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
+ for (int trackID = 0; trackID < mExtractor.getTrackCount(); trackID++) {
+ MediaFormat format = mExtractor.getTrackFormat(trackID);
+ String mime = format.getString(MediaFormat.KEY_MIME);
+ if (mime.startsWith("video/")) {
+ mExtractor.selectTrack(trackID);
+ format.setInteger(MediaFormat.KEY_COLOR_FORMAT,
+ MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible);
+ return format;
+ }
+ }
+ mExtractor.release();
+ return null;
+ }
+
+ private MediaFormat setUpEncoderFormat(MediaFormat decoderFormat) {
+ MediaFormat encoderFormat = new MediaFormat();
+ encoderFormat.setString(MediaFormat.KEY_MIME, mMime);
+ encoderFormat
+ .setInteger(MediaFormat.KEY_WIDTH, decoderFormat.getInteger(MediaFormat.KEY_WIDTH));
+ encoderFormat.setInteger(MediaFormat.KEY_HEIGHT,
+ decoderFormat.getInteger(MediaFormat.KEY_HEIGHT));
+ encoderFormat.setInteger(MediaFormat.KEY_FRAME_RATE, VIDEO_FRAMERATE);
+ encoderFormat.setInteger(MediaFormat.KEY_BIT_RATE, VIDEO_BITRATE);
+ encoderFormat.setFloat(MediaFormat.KEY_I_FRAME_INTERVAL, 1.0f);
+ encoderFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT,
+ MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
+ if (mMime.equals(MediaFormat.MIMETYPE_VIDEO_HEVC)) {
+ encoderFormat.setInteger(MediaFormat.KEY_PROFILE,
+ MediaCodecInfo.CodecProfileLevel.HEVCProfileMain);
+ encoderFormat.setInteger(MediaFormat.KEY_LEVEL,
+ MediaCodecInfo.CodecProfileLevel.HEVCMainTierLevel4);
+ } else {
+ encoderFormat.setInteger(MediaFormat.KEY_PROFILE,
+ MediaCodecInfo.CodecProfileLevel.AVCProfileMain);
+ encoderFormat
+ .setInteger(MediaFormat.KEY_LEVEL, MediaCodecInfo.CodecProfileLevel.AVCLevel4);
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ encoderFormat.setInteger(MediaFormat.KEY_MAX_B_FRAMES, mMaxBFrames);
+ } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ encoderFormat.setInteger(MediaFormat.KEY_LATENCY, 1);
+ }
+ return encoderFormat;
+ }
+
+ private void resetContext() {
+ mAsyncHandleDecoder.resetContext();
+ mAsyncHandleEncoder.resetContext();
+ mSawDecInputEOS = false;
+ mSawDecOutputEOS = false;
+ mSawEncOutputEOS = false;
+ mDecOutputCount = 0;
+ mEncOutputCount = 0;
+ }
+
+ private void configureCodec(MediaFormat decFormat, MediaFormat encFormat) {
+ resetContext();
+ mAsyncHandleEncoder.setCallBack(mEncoder, true);
+ mEncoder.configure(encFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
+ mSurface = mEncoder.createInputSurface();
+ if (!mSurface.isValid()) {
+ Log.e(TAG, "Surface is not valid");
+ return;
+ }
+ mAsyncHandleDecoder.setCallBack(mDecoder, true);
+ mDecoder.configure(decFormat, mSurface, null, 0);
+ Log.d(TAG, "Codec configured");
+ if (DEBUG) {
+ Log.d(TAG, "Encoder Output format: " + mEncoder.getOutputFormat());
+ }
+ }
+
+ private void dequeueDecoderOutput(int bufferIndex, MediaCodec.BufferInfo info) {
+ if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+ mSawDecOutputEOS = true;
+ }
+ if (DEBUG) {
+ Log.d(TAG,
+ "output: id: " + bufferIndex + " flags: " + info.flags + " size: " + info.size +
+ " timestamp: " + info.presentationTimeUs);
+ }
+ if (info.size > 0 && (info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) {
+ mDecOutputCount++;
+ }
+ mDecoder.releaseOutputBuffer(bufferIndex, mSurface != null);
+ }
+
+ private void enqueueDecoderInput(int bufferIndex) {
+ ByteBuffer inputBuffer = mDecoder.getInputBuffer(bufferIndex);
+ int size = mExtractor.readSampleData(inputBuffer, 0);
+ if (size < 0) {
+ enqueueDecoderEOS(bufferIndex);
+ } else {
+ long pts = mExtractor.getSampleTime();
+ int extractorFlags = mExtractor.getSampleFlags();
+ int codecFlags = 0;
+ if ((extractorFlags & MediaExtractor.SAMPLE_FLAG_SYNC) != 0) {
+ codecFlags |= MediaCodec.BUFFER_FLAG_KEY_FRAME;
+ }
+ if ((extractorFlags & MediaExtractor.SAMPLE_FLAG_PARTIAL_FRAME) != 0) {
+ codecFlags |= MediaCodec.BUFFER_FLAG_PARTIAL_FRAME;
+ }
+ if (!mExtractor.advance()) {
+ codecFlags |= MediaCodec.BUFFER_FLAG_END_OF_STREAM;
+ mSawDecInputEOS = true;
+ }
+ if (DEBUG) {
+ Log.d(TAG, "input: id: " + bufferIndex + " size: " + size + " pts: " + pts +
+ " flags: " + codecFlags);
+ }
+ mDecoder.queueInputBuffer(bufferIndex, 0, size, pts, codecFlags);
+ }
+ }
+
+ private void doWork(int frameLimit) throws InterruptedException {
+ int frameCount = 0;
+ while (!hasSeenError() && !mSawDecInputEOS && frameCount < frameLimit) {
+ Pair<Integer, MediaCodec.BufferInfo> element = mAsyncHandleDecoder.getWork();
+ if (element != null) {
+ int bufferID = element.first;
+ MediaCodec.BufferInfo info = element.second;
+ if (info != null) {
+ // <id, info> corresponds to output callback.
+ dequeueDecoderOutput(bufferID, info);
+ } else {
+ // <id, null> corresponds to input callback.
+ enqueueDecoderInput(bufferID);
+ frameCount++;
+ }
+ }
+ // check decoder EOS
+ if (mSawDecOutputEOS) mEncoder.signalEndOfInputStream();
+ // encoder output
+ if (mDecOutputCount - mEncOutputCount > mMaxBFrames) {
+ tryEncoderOutput();
+ }
+ }
+ }
+
+ private void queueEOS() throws InterruptedException {
+ while (!mAsyncHandleDecoder.hasSeenError() && !mSawDecInputEOS) {
+ Pair<Integer, MediaCodec.BufferInfo> element = mAsyncHandleDecoder.getWork();
+ if (element != null) {
+ int bufferID = element.first;
+ MediaCodec.BufferInfo info = element.second;
+ if (info != null) {
+ dequeueDecoderOutput(bufferID, info);
+ } else {
+ enqueueDecoderEOS(element.first);
+ }
+ }
+ }
+
+ while (!hasSeenError() && !mSawDecOutputEOS) {
+ Pair<Integer, MediaCodec.BufferInfo> decOp = mAsyncHandleDecoder.getOutput();
+ if (decOp != null) dequeueDecoderOutput(decOp.first, decOp.second);
+ if (mSawDecOutputEOS) mEncoder.signalEndOfInputStream();
+ if (mDecOutputCount - mEncOutputCount > mMaxBFrames) {
+ tryEncoderOutput();
+ }
+ }
+ }
+
+ private void tryEncoderOutput() throws InterruptedException {
+ if (!hasSeenError() && !mSawEncOutputEOS) {
+ Pair<Integer, MediaCodec.BufferInfo> element = mAsyncHandleEncoder.getOutput();
+ if (element != null) {
+ dequeueEncoderOutput(element.first, element.second);
+ }
+ }
+ }
+
+ private void waitForAllEncoderOutputs() throws InterruptedException {
+ while (!hasSeenError() && !mSawEncOutputEOS) {
+ tryEncoderOutput();
+ }
+ }
+
+ private void enqueueDecoderEOS(int bufferIndex) {
+ if (!mSawDecInputEOS) {
+ mDecoder.queueInputBuffer(bufferIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
+ mSawDecInputEOS = true;
+ Log.d(TAG, "Queued End of Stream");
+ }
+ }
+
+ private void dequeueEncoderOutput(int bufferIndex, MediaCodec.BufferInfo info) {
+ if (DEBUG) {
+ Log.d(TAG, "encoder output: id: " + bufferIndex + " flags: " + info.flags + " size: " +
+ info.size + " timestamp: " + info.presentationTimeUs);
+ }
+ if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+ mSawEncOutputEOS = true;
+ }
+ if (info.size > 0) {
+ ByteBuffer buf = mEncoder.getOutputBuffer(bufferIndex);
+ if (mMuxer != null) {
+ if (mTrackID == -1) {
+ mTrackID = mMuxer.addTrack(mEncoder.getOutputFormat());
+ mMuxer.start();
+ }
+ mMuxer.writeSampleData(mTrackID, buf, info);
+ }
+ if ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) {
+ mEncOutputCount++;
+ }
+ }
+ mEncoder.releaseOutputBuffer(bufferIndex, false);
+ }
+
+ private boolean hasSeenError() {
+ return mAsyncHandleDecoder.hasSeenError() || mAsyncHandleEncoder.hasSeenError();
+ }
+}
diff --git a/media/tests/SampleVideoEncoder/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/media/tests/SampleVideoEncoder/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000..2b068d1
--- /dev/null
+++ b/media/tests/SampleVideoEncoder/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
+ <aapt:attr name="android:fillColor">
+ <gradient
+ android:endX="85.84757"
+ android:endY="92.4963"
+ android:startX="42.9492"
+ android:startY="49.59793"
+ android:type="linear">
+ <item
+ android:color="#44000000"
+ android:offset="0.0" />
+ <item
+ android:color="#00000000"
+ android:offset="1.0" />
+ </gradient>
+ </aapt:attr>
+ </path>
+ <path
+ android:fillColor="#FFFFFF"
+ android:fillType="nonZero"
+ android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
+ android:strokeWidth="1"
+ android:strokeColor="#00000000" />
+</vector>
\ No newline at end of file
diff --git a/media/tests/SampleVideoEncoder/app/src/main/res/drawable/ic_launcher_background.xml b/media/tests/SampleVideoEncoder/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..07d5da9
--- /dev/null
+++ b/media/tests/SampleVideoEncoder/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <path
+ android:fillColor="#3DDC84"
+ android:pathData="M0,0h108v108h-108z" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M9,0L9,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,0L19,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M29,0L29,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M39,0L39,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M49,0L49,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M59,0L59,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M69,0L69,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M79,0L79,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M89,0L89,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M99,0L99,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,9L108,9"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,19L108,19"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,29L108,29"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,39L108,39"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,49L108,49"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,59L108,59"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,69L108,69"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,79L108,79"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,89L108,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,99L108,99"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,29L89,29"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,39L89,39"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,49L89,49"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,59L89,59"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,69L89,69"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,79L89,79"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M29,19L29,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M39,19L39,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M49,19L49,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M59,19L59,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M69,19L69,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M79,19L79,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+</vector>
diff --git a/media/tests/SampleVideoEncoder/app/src/main/res/layout/activity_main.xml b/media/tests/SampleVideoEncoder/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..164e02a
--- /dev/null
+++ b/media/tests/SampleVideoEncoder/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ tools:context="com.android.media.samplevideoencoder.MainActivity">
+
+ <com.android.media.samplevideoencoder.AutoFitTextureView
+ android:id="@+id/texture"
+ android:layout_width="wrap_content"
+ android:layout_height="300dp"
+ android:layout_alignParentStart="true"
+ android:layout_alignParentTop="true"
+ android:layout_marginBottom="16dp"
+ android:gravity="center"
+ app:layout_constraintBottom_toTopOf="@+id/checkBox_media_recorder"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <CheckBox
+ android:id="@+id/checkBox_media_recorder"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="90dp"
+ android:layout_marginTop="10dp"
+ android:fontFamily="sans-serif-medium"
+ android:text="@string/media_recorder"
+ android:textAppearance="@style/TextAppearance.AppCompat.Large"
+ android:textStyle="normal"
+ android:checked="true"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/texture"/>
+
+ <CheckBox
+ android:id="@+id/checkBox_media_codec"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="90dp"
+ android:fontFamily="sans-serif-medium"
+ android:text="@string/media_codec"
+ android:textAppearance="@style/TextAppearance.AppCompat.Large"
+ android:textStyle="normal"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/checkBox_media_recorder" />
+
+ <RadioGroup
+ android:id="@+id/radio_group_mime"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="40dp"
+ android:layout_marginTop="10dp"
+ android:orientation="vertical"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintBottom_toTopOf="@+id/frameLayout2"
+ app:layout_constraintTop_toBottomOf="@+id/checkBox_media_codec">
+
+ <RadioButton
+ android:id="@+id/avc"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:checked="true"
+ android:text="@string/avc" />
+
+ <RadioButton
+ android:id="@+id/hevc"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/hevc" />
+ </RadioGroup>
+
+ <RadioGroup
+ android:id="@+id/radio_group_codec"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="10dp"
+ android:layout_marginEnd="40dp"
+ android:orientation="vertical"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/checkBox_media_codec">
+
+ <RadioButton
+ android:id="@+id/hw"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:checked="true"
+ android:enabled="false"
+ android:text="@string/hardware" />
+
+ <RadioButton
+ android:id="@+id/sw"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:enabled="false"
+ android:text="@string/software" />
+ </RadioGroup>
+
+ <FrameLayout
+ android:id="@+id/frameLayout2"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/radio_group_mime"
+ android:layout_alignParentStart="true"
+ android:layout_alignParentBottom="true"
+ android:layout_marginTop="10dp"
+ android:background="@color/colorPrimary"
+ app:layout_constraintTop_toBottomOf="@+id/radio_group_mime"
+ tools:layout_editor_absoluteX="80dp">
+
+ <Button
+ android:id="@+id/start_button"
+ android:layout_width="108dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:text="@string/start_button"
+ tools:layout_editor_absoluteX="155dp"
+ tools:layout_editor_absoluteY="455dp" />
+
+ </FrameLayout>
+
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/media/tests/SampleVideoEncoder/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/media/tests/SampleVideoEncoder/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/media/tests/SampleVideoEncoder/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@drawable/ic_launcher_background" />
+ <foreground android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon>
\ No newline at end of file
diff --git a/media/tests/SampleVideoEncoder/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/media/tests/SampleVideoEncoder/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/media/tests/SampleVideoEncoder/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@drawable/ic_launcher_background" />
+ <foreground android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon>
\ No newline at end of file
diff --git a/media/tests/SampleVideoEncoder/app/src/main/res/raw/crowd_1920x1080_25fps_4000kbps_h265.mp4 b/media/tests/SampleVideoEncoder/app/src/main/res/raw/crowd_1920x1080_25fps_4000kbps_h265.mp4
new file mode 100644
index 0000000..6204008
--- /dev/null
+++ b/media/tests/SampleVideoEncoder/app/src/main/res/raw/crowd_1920x1080_25fps_4000kbps_h265.mp4
Binary files differ
diff --git a/media/tests/SampleVideoEncoder/app/src/main/res/values/colors.xml b/media/tests/SampleVideoEncoder/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..4faecfa
--- /dev/null
+++ b/media/tests/SampleVideoEncoder/app/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <color name="colorPrimary">#6200EE</color>
+ <color name="colorPrimaryDark">#3700B3</color>
+ <color name="colorAccent">#03DAC5</color>
+</resources>
\ No newline at end of file
diff --git a/media/tests/SampleVideoEncoder/app/src/main/res/values/strings.xml b/media/tests/SampleVideoEncoder/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..f825a7f
--- /dev/null
+++ b/media/tests/SampleVideoEncoder/app/src/main/res/values/strings.xml
@@ -0,0 +1,13 @@
+<resources>
+ <string name="app_name">SampleVideoEncoder</string>
+ <string name="media_recorder">MediaRecorder</string>
+ <string name="media_codec">MediaCodec</string>
+ <string name="start_button">Start</string>
+ <string name="stop">Stop</string>
+ <string name="start">Start</string>
+ <string name="avc">AVC</string>
+ <string name="hevc">HEVC</string>
+ <string name="hardware">H/W</string>
+ <string name="software">S/W</string>
+
+</resources>
\ No newline at end of file
diff --git a/media/tests/SampleVideoEncoder/app/src/main/res/values/styles.xml b/media/tests/SampleVideoEncoder/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..fac9291
--- /dev/null
+++ b/media/tests/SampleVideoEncoder/app/src/main/res/values/styles.xml
@@ -0,0 +1,10 @@
+<resources>
+ <!-- Base application theme. -->
+ <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
+ <!-- Customize your theme here. -->
+ <item name="colorPrimary">@color/colorPrimary</item>
+ <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
+ <item name="colorAccent">@color/colorAccent</item>
+ </style>
+
+</resources>
\ No newline at end of file
diff --git a/media/tests/SampleVideoEncoder/build.gradle b/media/tests/SampleVideoEncoder/build.gradle
new file mode 100644
index 0000000..4ca0c7e
--- /dev/null
+++ b/media/tests/SampleVideoEncoder/build.gradle
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+buildscript {
+ repositories {
+ google()
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:4.1.1'
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ jcenter()
+ }
+}
\ No newline at end of file
diff --git a/media/tests/SampleVideoEncoder/gradle.properties b/media/tests/SampleVideoEncoder/gradle.properties
new file mode 100644
index 0000000..5ae443b
--- /dev/null
+++ b/media/tests/SampleVideoEncoder/gradle.properties
@@ -0,0 +1,4 @@
+# Project-wide Gradle settings.
+org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
+android.useAndroidX=true
+android.enableJetifier=true
diff --git a/media/tests/SampleVideoEncoder/gradle/wrapper/gradle-wrapper.jar b/media/tests/SampleVideoEncoder/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..f6b961f
--- /dev/null
+++ b/media/tests/SampleVideoEncoder/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/media/tests/SampleVideoEncoder/gradle/wrapper/gradle-wrapper.properties b/media/tests/SampleVideoEncoder/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..a9a12eb
--- /dev/null
+++ b/media/tests/SampleVideoEncoder/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Dec 16 10:06:45 IST 2020
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
diff --git a/media/tests/SampleVideoEncoder/gradlew b/media/tests/SampleVideoEncoder/gradlew
new file mode 100644
index 0000000..cccdd3d
--- /dev/null
+++ b/media/tests/SampleVideoEncoder/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/media/tests/SampleVideoEncoder/gradlew.bat b/media/tests/SampleVideoEncoder/gradlew.bat
new file mode 100644
index 0000000..f955316
--- /dev/null
+++ b/media/tests/SampleVideoEncoder/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/media/tests/SampleVideoEncoder/settings.gradle b/media/tests/SampleVideoEncoder/settings.gradle
new file mode 100644
index 0000000..4d3c3a5
--- /dev/null
+++ b/media/tests/SampleVideoEncoder/settings.gradle
@@ -0,0 +1,2 @@
+include ':app'
+rootProject.name = "SampleVideoEncoder"
\ No newline at end of file
diff --git a/media/utils/Android.bp b/media/utils/Android.bp
index ec77bd0..26cdc3a 100644
--- a/media/utils/Android.bp
+++ b/media/utils/Android.bp
@@ -39,6 +39,7 @@
"libc_malloc_debug_backtrace",
],
shared_libs: [
+ "libaudioclient_aidl_conversion",
"libaudioutils", // for clock.h
"libbinder",
"libcutils",
@@ -47,6 +48,7 @@
"libhidlbase",
"android.hardware.graphics.bufferqueue@1.0",
"android.hidl.token@1.0-utils",
+ "media_permission-aidl-cpp",
],
logtags: ["EventLogTags.logtags"],
@@ -62,6 +64,10 @@
"libmedia_headers",
],
+ export_shared_lib_headers: [
+ "media_permission-aidl-cpp"
+ ],
+
include_dirs: [
// For DEBUGGER_SIGNAL
"system/core/debuggerd/include",
diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp
index 2c8a452..e2e1043 100644
--- a/media/utils/ServiceUtilities.cpp
+++ b/media/utils/ServiceUtilities.cpp
@@ -23,6 +23,9 @@
#include <binder/PermissionCache.h>
#include "mediautils/ServiceUtilities.h"
#include <system/audio-hal-enums.h>
+#include <media/AidlConversion.h>
+#include <media/AidlConversionUtil.h>
+#include <android/media/permission/Identity.h>
#include <iterator>
#include <algorithm>
@@ -37,14 +40,16 @@
namespace android {
+using media::permission::Identity;
+
static const String16 sAndroidPermissionRecordAudio("android.permission.RECORD_AUDIO");
static const String16 sModifyPhoneState("android.permission.MODIFY_PHONE_STATE");
static const String16 sModifyAudioRouting("android.permission.MODIFY_AUDIO_ROUTING");
static String16 resolveCallingPackage(PermissionController& permissionController,
- const String16& opPackageName, uid_t uid) {
- if (opPackageName.size() > 0) {
- return opPackageName;
+ const std::optional<String16> opPackageName, uid_t uid) {
+ if (opPackageName.has_value() && opPackageName.value().size() > 0) {
+ return opPackageName.value();
}
// In some cases the calling code has no access to the package it runs under.
// For example, code using the wilhelm framework's OpenSL-ES APIs. In this
@@ -57,7 +62,7 @@
permissionController.getPackagesForUid(uid, packages);
if (packages.isEmpty()) {
ALOGE("No packages for uid %d", uid);
- return opPackageName; // empty string
+ return String16();
}
return packages[0];
}
@@ -74,47 +79,52 @@
}
}
-static bool checkRecordingInternal(const String16& opPackageName, pid_t pid,
- uid_t uid, bool start, audio_source_t source) {
+static bool checkRecordingInternal(const Identity& identity, const String16& msg,
+ bool start, audio_source_t source) {
// Okay to not track in app ops as audio server or media server is us and if
// device is rooted security model is considered compromised.
// system_server loses its RECORD_AUDIO permission when a secondary
// user is active, but it is a core system service so let it through.
// TODO(b/141210120): UserManager.DISALLOW_RECORD_AUDIO should not affect system user 0
+ uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.uid));
if (isAudioServerOrMediaServerOrSystemServerOrRootUid(uid)) return true;
// We specify a pid and uid here as mediaserver (aka MediaRecorder or StageFrightRecorder)
// may open a record track on behalf of a client. Note that pid may be a tid.
// IMPORTANT: DON'T USE PermissionCache - RUNTIME PERMISSIONS CHANGE.
PermissionController permissionController;
- const bool ok = permissionController.checkPermission(sAndroidPermissionRecordAudio, pid, uid);
+ const bool ok = permissionController.checkPermission(sAndroidPermissionRecordAudio,
+ identity.pid, identity.uid);
if (!ok) {
ALOGE("Request requires %s", String8(sAndroidPermissionRecordAudio).c_str());
return false;
}
String16 resolvedOpPackageName = resolveCallingPackage(
- permissionController, opPackageName, uid);
+ permissionController, VALUE_OR_FATAL(aidl2legacy_string_view_String16(
+ identity.packageName.value_or(""))), uid);
if (resolvedOpPackageName.size() == 0) {
return false;
}
+
AppOpsManager appOps;
const int32_t op = getOpForSource(source);
if (start) {
- if (int32_t mode = appOps.startOpNoThrow(
- op, uid, resolvedOpPackageName, /*startIfModeDefault*/ false);
- mode != AppOpsManager::MODE_ALLOWED) {
+ if (int32_t mode = appOps.startOpNoThrow(op, identity.uid,
+ resolvedOpPackageName, /*startIfModeDefault*/ false,
+ VALUE_OR_FATAL(aidl2legacy_optional_string_view_optional_String16(
+ identity.attributionTag)), msg) != AppOpsManager::MODE_ALLOWED) {
ALOGE("Request start for \"%s\" (uid %d) denied by app op: %d, mode: %d",
- String8(resolvedOpPackageName).c_str(), uid, op, mode);
+ String8(resolvedOpPackageName).c_str(), identity.uid, op, mode);
return false;
}
} else {
// Always use OP_RECORD_AUDIO for checks at creation time.
- if (int32_t mode = appOps.checkOp(op, uid, resolvedOpPackageName);
- mode != AppOpsManager::MODE_ALLOWED) {
+ if (int32_t mode = appOps.checkOp(op, uid,
+ resolvedOpPackageName) != AppOpsManager::MODE_ALLOWED) {
ALOGE("Request check for \"%s\" (uid %d) denied by app op: %d, mode: %d",
- String8(resolvedOpPackageName).c_str(), uid, op, mode);
+ String8(resolvedOpPackageName).c_str(), identity.uid, op, mode);
return false;
}
}
@@ -122,22 +132,25 @@
return true;
}
-bool recordingAllowed(const String16& opPackageName, pid_t pid, uid_t uid) {
- return checkRecordingInternal(opPackageName, pid, uid, /*start*/ false, AUDIO_SOURCE_DEFAULT);
+bool recordingAllowed(const Identity& identity) {
+ return checkRecordingInternal(identity, String16(), /*start*/ false, AUDIO_SOURCE_DEFAULT);
}
-bool startRecording(const String16& opPackageName, pid_t pid, uid_t uid, audio_source_t source) {
- return checkRecordingInternal(opPackageName, pid, uid, /*start*/ true, source);
+bool startRecording(const Identity& identity, const String16& msg, audio_source_t source) {
+ return checkRecordingInternal(identity, msg, /*start*/ true, source);
}
-void finishRecording(const String16& opPackageName, uid_t uid, audio_source_t source) {
+void finishRecording(const Identity& identity, audio_source_t source) {
// Okay to not track in app ops as audio server is us and if
// device is rooted security model is considered compromised.
+ uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.uid));
if (isAudioServerOrRootUid(uid)) return;
PermissionController permissionController;
String16 resolvedOpPackageName = resolveCallingPackage(
- permissionController, opPackageName, uid);
+ permissionController,
+ VALUE_OR_FATAL(aidl2legacy_string_view_String16(identity.packageName.value_or(""))),
+ VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.uid)));
if (resolvedOpPackageName.size() == 0) {
return;
}
@@ -145,10 +158,14 @@
AppOpsManager appOps;
const int32_t op = getOpForSource(source);
- appOps.finishOp(op, uid, resolvedOpPackageName);
+ appOps.finishOp(op, identity.uid, resolvedOpPackageName,
+ VALUE_OR_FATAL(aidl2legacy_optional_string_view_optional_String16(
+ identity.attributionTag)));
}
-bool captureAudioOutputAllowed(pid_t pid, uid_t uid) {
+bool captureAudioOutputAllowed(const Identity& identity) {
+ uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.uid));
+ pid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(identity.pid));
if (isAudioServerOrRootUid(uid)) return true;
static const String16 sCaptureAudioOutput("android.permission.CAPTURE_AUDIO_OUTPUT");
bool ok = PermissionCache::checkPermission(sCaptureAudioOutput, pid, uid);
@@ -156,7 +173,9 @@
return ok;
}
-bool captureMediaOutputAllowed(pid_t pid, uid_t uid) {
+bool captureMediaOutputAllowed(const Identity& identity) {
+ uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.uid));
+ pid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(identity.pid));
if (isAudioServerOrRootUid(uid)) return true;
static const String16 sCaptureMediaOutput("android.permission.CAPTURE_MEDIA_OUTPUT");
bool ok = PermissionCache::checkPermission(sCaptureMediaOutput, pid, uid);
@@ -164,7 +183,9 @@
return ok;
}
-bool captureTunerAudioInputAllowed(pid_t pid, uid_t uid) {
+bool captureTunerAudioInputAllowed(const Identity& identity) {
+ uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.uid));
+ pid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(identity.pid));
if (isAudioServerOrRootUid(uid)) return true;
static const String16 sCaptureTunerAudioInput("android.permission.CAPTURE_TUNER_AUDIO_INPUT");
bool ok = PermissionCache::checkPermission(sCaptureTunerAudioInput, pid, uid);
@@ -172,7 +193,9 @@
return ok;
}
-bool captureVoiceCommunicationOutputAllowed(pid_t pid, uid_t uid) {
+bool captureVoiceCommunicationOutputAllowed(const Identity& identity) {
+ uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.uid));
+ uid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(identity.pid));
if (isAudioServerOrRootUid(uid)) return true;
static const String16 sCaptureVoiceCommOutput(
"android.permission.CAPTURE_VOICE_COMMUNICATION_OUTPUT");
@@ -181,9 +204,11 @@
return ok;
}
-bool captureHotwordAllowed(const String16& opPackageName, pid_t pid, uid_t uid) {
+bool captureHotwordAllowed(const Identity& identity) {
+ uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.uid));
+ uid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(identity.pid));
// CAPTURE_AUDIO_HOTWORD permission implies RECORD_AUDIO permission
- bool ok = recordingAllowed(opPackageName, pid, uid);
+ bool ok = recordingAllowed(identity);
if (ok) {
static const String16 sCaptureHotwordAllowed("android.permission.CAPTURE_AUDIO_HOTWORD");
@@ -205,11 +230,12 @@
}
bool modifyAudioRoutingAllowed() {
- return modifyAudioRoutingAllowed(
- IPCThreadState::self()->getCallingPid(), IPCThreadState::self()->getCallingUid());
+ return modifyAudioRoutingAllowed(getCallingIdentity());
}
-bool modifyAudioRoutingAllowed(pid_t pid, uid_t uid) {
+bool modifyAudioRoutingAllowed(const Identity& identity) {
+ uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.uid));
+ pid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(identity.pid));
if (isAudioServerUid(IPCThreadState::self()->getCallingUid())) return true;
// IMPORTANT: Use PermissionCache - not a runtime permission and may not change.
bool ok = PermissionCache::checkPermission(sModifyAudioRouting, pid, uid);
@@ -219,11 +245,12 @@
}
bool modifyDefaultAudioEffectsAllowed() {
- return modifyDefaultAudioEffectsAllowed(
- IPCThreadState::self()->getCallingPid(), IPCThreadState::self()->getCallingUid());
+ return modifyDefaultAudioEffectsAllowed(getCallingIdentity());
}
-bool modifyDefaultAudioEffectsAllowed(pid_t pid, uid_t uid) {
+bool modifyDefaultAudioEffectsAllowed(const Identity& identity) {
+ uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.uid));
+ pid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(identity.pid));
if (isAudioServerUid(IPCThreadState::self()->getCallingUid())) return true;
static const String16 sModifyDefaultAudioEffectsAllowed(
@@ -244,14 +271,18 @@
return ok;
}
-bool modifyPhoneStateAllowed(pid_t pid, uid_t uid) {
+bool modifyPhoneStateAllowed(const Identity& identity) {
+ uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.uid));
+ pid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(identity.pid));
bool ok = PermissionCache::checkPermission(sModifyPhoneState, pid, uid);
ALOGE_IF(!ok, "Request requires %s", String8(sModifyPhoneState).c_str());
return ok;
}
// privileged behavior needed by Dialer, Settings, SetupWizard and CellBroadcastReceiver
-bool bypassInterruptionPolicyAllowed(pid_t pid, uid_t uid) {
+bool bypassInterruptionPolicyAllowed(const Identity& identity) {
+ uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.uid));
+ pid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(identity.pid));
static const String16 sWriteSecureSettings("android.permission.WRITE_SECURE_SETTINGS");
bool ok = PermissionCache::checkPermission(sModifyPhoneState, pid, uid)
|| PermissionCache::checkPermission(sWriteSecureSettings, pid, uid)
@@ -261,6 +292,13 @@
return ok;
}
+Identity getCallingIdentity() {
+ Identity identity = Identity();
+ identity.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(IPCThreadState::self()->getCallingPid()));
+ identity.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(IPCThreadState::self()->getCallingUid()));
+ return identity;
+}
+
status_t checkIMemory(const sp<IMemory>& iMemory)
{
if (iMemory == 0) {
diff --git a/media/utils/TimeCheck.cpp b/media/utils/TimeCheck.cpp
index 59d74de..819e146 100644
--- a/media/utils/TimeCheck.cpp
+++ b/media/utils/TimeCheck.cpp
@@ -39,10 +39,9 @@
static std::atomic<int> curAudioHalPids = 0;
if (update) {
- audioHalPids[(curAudioHalPids + 1) % kNumAudioHalPidsVectors] = *pids;
- curAudioHalPids++;
+ audioHalPids[(curAudioHalPids++ + 1) % kNumAudioHalPidsVectors] = *pids;
} else {
- *pids = audioHalPids[curAudioHalPids];
+ *pids = audioHalPids[curAudioHalPids % kNumAudioHalPidsVectors];
}
}
diff --git a/media/utils/fuzzers/Android.bp b/media/utils/fuzzers/Android.bp
index 80882b2..187ef7c 100644
--- a/media/utils/fuzzers/Android.bp
+++ b/media/utils/fuzzers/Android.bp
@@ -15,6 +15,7 @@
"liblog",
"libmediautils",
"libutils",
+ "media_permission-aidl-cpp",
],
cflags: [
diff --git a/media/utils/fuzzers/ServiceUtilitiesFuzz.cpp b/media/utils/fuzzers/ServiceUtilitiesFuzz.cpp
index f4c815c..2f9e780 100644
--- a/media/utils/fuzzers/ServiceUtilitiesFuzz.cpp
+++ b/media/utils/fuzzers/ServiceUtilitiesFuzz.cpp
@@ -19,12 +19,15 @@
#include <functional>
#include <type_traits>
+#include <android/media/permission/Identity.h>
#include "fuzzer/FuzzedDataProvider.h"
#include "mediautils/ServiceUtilities.h"
static constexpr int kMaxOperations = 50;
static constexpr int kMaxStringLen = 256;
+using android::media::permission::Identity;
+
const std::vector<std::function<void(FuzzedDataProvider*, android::MediaPackageManager)>>
operations = {
[](FuzzedDataProvider* data_provider, android::MediaPackageManager pm) -> void {
@@ -43,27 +46,33 @@
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
FuzzedDataProvider data_provider(data, size);
- uid_t uid = data_provider.ConsumeIntegral<uid_t>();
- pid_t pid = data_provider.ConsumeIntegral<pid_t>();
+ int32_t uid = data_provider.ConsumeIntegral<int32_t>();
+ int32_t pid = data_provider.ConsumeIntegral<int32_t>();
audio_source_t source = static_cast<audio_source_t>(data_provider
.ConsumeIntegral<std::underlying_type_t<audio_source_t>>());
+ std::string packageNameStr = data_provider.ConsumeRandomLengthString(kMaxStringLen);
+ std::string msgStr = data_provider.ConsumeRandomLengthString(kMaxStringLen);
+ android::String16 msgStr16(packageNameStr.c_str());
+ Identity identity;
+ identity.packageName = packageNameStr;
+ identity.uid = uid;
+ identity.pid = pid;
+
// There is not state here, and order is not significant,
// so we can simply call all of the target functions
android::isServiceUid(uid);
android::isAudioServerUid(uid);
android::isAudioServerOrSystemServerUid(uid);
android::isAudioServerOrMediaServerUid(uid);
- std::string packageNameStr = data_provider.ConsumeRandomLengthString(kMaxStringLen);
- android::String16 opPackageName(packageNameStr.c_str());
- android::recordingAllowed(opPackageName, pid, uid);
- android::startRecording(opPackageName, pid, uid, source);
- android::finishRecording(opPackageName, uid, source);
- android::captureAudioOutputAllowed(pid, uid);
- android::captureMediaOutputAllowed(pid, uid);
- android::captureHotwordAllowed(opPackageName, pid, uid);
- android::modifyPhoneStateAllowed(uid, pid);
- android::bypassInterruptionPolicyAllowed(uid, pid);
+ android::recordingAllowed(identity);
+ android::startRecording(identity, msgStr16, source);
+ android::finishRecording(identity, source);
+ android::captureAudioOutputAllowed(identity);
+ android::captureMediaOutputAllowed(identity);
+ android::captureHotwordAllowed(identity);
+ android::modifyPhoneStateAllowed(identity);
+ android::bypassInterruptionPolicyAllowed(identity);
android::settingsAllowed();
android::modifyAudioRoutingAllowed();
android::modifyDefaultAudioEffectsAllowed();
diff --git a/media/utils/include/mediautils/ServiceUtilities.h b/media/utils/include/mediautils/ServiceUtilities.h
index 03965db..9a3c6fb 100644
--- a/media/utils/include/mediautils/ServiceUtilities.h
+++ b/media/utils/include/mediautils/ServiceUtilities.h
@@ -25,6 +25,7 @@
#include <cutils/multiuser.h>
#include <private/android_filesystem_config.h>
#include <system/audio-hal-enums.h>
+#include <android/media/permission/Identity.h>
#include <map>
#include <optional>
@@ -79,22 +80,25 @@
}
}
-bool recordingAllowed(const String16& opPackageName, pid_t pid, uid_t uid);
-bool startRecording(const String16& opPackageName, pid_t pid, uid_t uid, audio_source_t source);
-void finishRecording(const String16& opPackageName, uid_t uid, audio_source_t source);
-bool captureAudioOutputAllowed(pid_t pid, uid_t uid);
-bool captureMediaOutputAllowed(pid_t pid, uid_t uid);
-bool captureTunerAudioInputAllowed(pid_t pid, uid_t uid);
-bool captureVoiceCommunicationOutputAllowed(pid_t pid, uid_t uid);
-bool captureHotwordAllowed(const String16& opPackageName, pid_t pid, uid_t uid);
+bool recordingAllowed(const media::permission::Identity& identity);
+bool startRecording(const media::permission::Identity& identity,
+ const String16& msg, audio_source_t source);
+void finishRecording(const media::permission::Identity& identity, audio_source_t source);
+bool captureAudioOutputAllowed(const media::permission::Identity& identity);
+bool captureMediaOutputAllowed(const media::permission::Identity& identity);
+bool captureTunerAudioInputAllowed(const media::permission::Identity& identity);
+bool captureVoiceCommunicationOutputAllowed(const media::permission::Identity& identity);
+bool captureHotwordAllowed(const media::permission::Identity& identity);
bool settingsAllowed();
bool modifyAudioRoutingAllowed();
-bool modifyAudioRoutingAllowed(pid_t pid, uid_t uid);
+bool modifyAudioRoutingAllowed(const media::permission::Identity& identity);
bool modifyDefaultAudioEffectsAllowed();
-bool modifyDefaultAudioEffectsAllowed(pid_t pid, uid_t uid);
+bool modifyDefaultAudioEffectsAllowed(const media::permission::Identity& identity);
bool dumpAllowed();
-bool modifyPhoneStateAllowed(pid_t pid, uid_t uid);
-bool bypassInterruptionPolicyAllowed(pid_t pid, uid_t uid);
+bool modifyPhoneStateAllowed(const media::permission::Identity& identity);
+bool bypassInterruptionPolicyAllowed(const media::permission::Identity& identity);
+
+media::permission::Identity getCallingIdentity();
status_t checkIMemory(const sp<IMemory>& iMemory);
diff --git a/services/audioflinger/Android.bp b/services/audioflinger/Android.bp
index 518ef9a..2294c49 100644
--- a/services/audioflinger/Android.bp
+++ b/services/audioflinger/Android.bp
@@ -80,6 +80,7 @@
"libmedia_helper",
"libshmemcompat",
"libvibrator",
+ "media_permission-aidl-cpp",
],
static_libs: [
@@ -93,6 +94,10 @@
"libmedia_headers",
],
+ export_shared_lib_headers: [
+ "media_permission-aidl-cpp",
+ ],
+
cflags: [
"-DSTATE_QUEUE_INSTANTIATIONS=\"StateQueueInstantiations.cpp\"",
"-fvisibility=hidden",
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index ae9fc64..6678287 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -85,15 +85,6 @@
#include "TypedLogger.h"
-#define VALUE_OR_FATAL(result) \
- ({ \
- auto _tmp = (result); \
- LOG_ALWAYS_FATAL_IF(!_tmp.ok(), \
- "Failed result (%d)", \
- _tmp.error()); \
- std::move(_tmp.value()); \
- })
-
// ----------------------------------------------------------------------------
// Note: the following macro is used for extremely verbose logging message. In
@@ -112,6 +103,7 @@
namespace android {
using media::IEffectClient;
+using media::permission::Identity;
static const char kDeadlockedString[] = "AudioFlinger may be deadlocked\n";
static const char kHardwareLockedString[] = "Hardware lock is taken\n";
@@ -364,7 +356,7 @@
ret = AudioSystem::getOutputForAttr(&localAttr, &io,
actualSessionId,
- &streamType, client.clientPid, client.clientUid,
+ &streamType, client.identity,
&fullConfig,
(audio_output_flags_t)(AUDIO_OUTPUT_FLAG_MMAP_NOIRQ |
AUDIO_OUTPUT_FLAG_DIRECT),
@@ -375,9 +367,7 @@
ret = AudioSystem::getInputForAttr(&localAttr, &io,
RECORD_RIID_INVALID,
actualSessionId,
- client.clientPid,
- client.clientUid,
- client.packageName,
+ client.identity,
config,
AUDIO_INPUT_FLAG_MMAP_NOIRQ, deviceId, &portId);
}
@@ -781,27 +771,33 @@
audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
std::vector<audio_io_handle_t> secondaryOutputs;
- bool updatePid = (input.clientInfo.clientPid == -1);
+ // TODO b/182392553: refactor or make clearer
+ pid_t clientPid =
+ VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_pid_t(input.clientInfo.identity.pid));
+ bool updatePid = (clientPid == (pid_t)-1);
const uid_t callingUid = IPCThreadState::self()->getCallingUid();
- uid_t clientUid = input.clientInfo.clientUid;
+ uid_t clientUid =
+ VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_uid_t(input.clientInfo.identity.uid));
audio_io_handle_t effectThreadId = AUDIO_IO_HANDLE_NONE;
std::vector<int> effectIds;
audio_attributes_t localAttr = input.attr;
+ Identity adjIdentity = input.clientInfo.identity;
if (!isAudioServerOrMediaServerUid(callingUid)) {
ALOGW_IF(clientUid != callingUid,
"%s uid %d tried to pass itself off as %d",
__FUNCTION__, callingUid, clientUid);
+ adjIdentity.uid = VALUE_OR_RETURN_STATUS(legacy2aidl_uid_t_int32_t(callingUid));
clientUid = callingUid;
updatePid = true;
}
- pid_t clientPid = input.clientInfo.clientPid;
const pid_t callingPid = IPCThreadState::self()->getCallingPid();
if (updatePid) {
- ALOGW_IF(clientPid != -1 && clientPid != callingPid,
+ ALOGW_IF(clientPid != (pid_t)-1 && clientPid != callingPid,
"%s uid %d pid %d tried to pass itself off as pid %d",
__func__, callingUid, callingPid, clientPid);
clientPid = callingPid;
+ adjIdentity.pid = VALUE_OR_RETURN_STATUS(legacy2aidl_pid_t_int32_t(callingPid));
}
audio_session_t sessionId = input.sessionId;
@@ -816,7 +812,7 @@
output.outputId = AUDIO_IO_HANDLE_NONE;
output.selectedDeviceId = input.selectedDeviceId;
lStatus = AudioSystem::getOutputForAttr(&localAttr, &output.outputId, sessionId, &streamType,
- clientPid, clientUid, &input.config, input.flags,
+ adjIdentity, &input.config, input.flags,
&output.selectedDeviceId, &portId, &secondaryOutputs);
if (lStatus != NO_ERROR || output.outputId == AUDIO_IO_HANDLE_NONE) {
@@ -881,9 +877,8 @@
&output.frameCount, &output.notificationFrameCount,
input.notificationsPerBuffer, input.speed,
input.sharedBuffer, sessionId, &output.flags,
- callingPid, input.clientInfo.clientTid, clientUid,
- &lStatus, portId, input.audioTrackCallback,
- input.opPackageName);
+ callingPid, adjIdentity, input.clientInfo.clientTid,
+ &lStatus, portId, input.audioTrackCallback);
LOG_ALWAYS_FATAL_IF((lStatus == NO_ERROR) && (track == 0));
// we don't abort yet if lStatus != NO_ERROR; there is still work to be done regardless
@@ -2041,23 +2036,25 @@
output.buffers.clear();
output.inputId = AUDIO_IO_HANDLE_NONE;
- bool updatePid = (input.clientInfo.clientPid == -1);
+ // TODO b/182392553: refactor or clean up
+ Identity adjIdentity = input.clientInfo.identity;
+ bool updatePid = (adjIdentity.pid == -1);
const uid_t callingUid = IPCThreadState::self()->getCallingUid();
- uid_t clientUid = input.clientInfo.clientUid;
+ const uid_t currentUid = VALUE_OR_RETURN_STATUS(legacy2aidl_uid_t_int32_t(adjIdentity.uid));
if (!isAudioServerOrMediaServerUid(callingUid)) {
- ALOGW_IF(clientUid != callingUid,
+ ALOGW_IF(currentUid != callingUid,
"%s uid %d tried to pass itself off as %d",
- __FUNCTION__, callingUid, clientUid);
- clientUid = callingUid;
+ __FUNCTION__, callingUid, currentUid);
+ adjIdentity.uid = VALUE_OR_RETURN_STATUS(legacy2aidl_uid_t_int32_t(callingUid));
updatePid = true;
}
- pid_t clientPid = input.clientInfo.clientPid;
const pid_t callingPid = IPCThreadState::self()->getCallingPid();
+ const pid_t currentPid = VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_pid_t(adjIdentity.pid));
if (updatePid) {
- ALOGW_IF(clientPid != -1 && clientPid != callingPid,
+ ALOGW_IF(currentPid != (pid_t)-1 && currentPid != callingPid,
"%s uid %d pid %d tried to pass itself off as pid %d",
- __func__, callingUid, callingPid, clientPid);
- clientPid = callingPid;
+ __func__, callingUid, callingPid, currentPid);
+ adjIdentity.pid = VALUE_OR_RETURN_STATUS(legacy2aidl_pid_t_int32_t(callingPid));
}
// we don't yet support anything other than linear PCM
@@ -2085,7 +2082,7 @@
output.selectedDeviceId = input.selectedDeviceId;
output.flags = input.flags;
- client = registerPid(clientPid);
+ client = registerPid(VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(adjIdentity.pid)));
// Not a conventional loop, but a retry loop for at most two iterations total.
// Try first maybe with FAST flag then try again without FAST flag if that fails.
@@ -2105,9 +2102,7 @@
input.riid,
sessionId,
// FIXME compare to AudioTrack
- clientPid,
- clientUid,
- input.opPackageName,
+ adjIdentity,
&input.config,
output.flags, &output.selectedDeviceId, &portId);
if (lStatus != NO_ERROR) {
@@ -2134,10 +2129,9 @@
input.config.format, input.config.channel_mask,
&output.frameCount, sessionId,
&output.notificationFrameCount,
- callingPid, clientUid, &output.flags,
+ callingPid, adjIdentity, &output.flags,
input.clientInfo.clientTid,
- &lStatus, portId,
- input.opPackageName);
+ &lStatus, portId);
LOG_ALWAYS_FATAL_IF((lStatus == NO_ERROR) && (recordTrack == 0));
// lStatus == BAD_TYPE means FAST flag was rejected: request a new input from
@@ -3530,9 +3524,7 @@
const int32_t priority = request.priority;
const AudioDeviceTypeAddr device = VALUE_OR_RETURN_STATUS(
aidl2legacy_AudioDeviceTypeAddress(request.device));
- const String16 opPackageName = VALUE_OR_RETURN_STATUS(
- aidl2legacy_string_view_String16(request.opPackageName));
- pid_t pid = VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_pid_t(request.pid));
+ Identity adjIdentity = request.identity;
const audio_session_t sessionId = VALUE_OR_RETURN_STATUS(
aidl2legacy_int32_t_audio_session_t(request.sessionId));
audio_io_handle_t io = VALUE_OR_RETURN_STATUS(
@@ -3548,17 +3540,21 @@
status_t lStatus = NO_ERROR;
+ // TODO b/182392553: refactor or make clearer
const uid_t callingUid = IPCThreadState::self()->getCallingUid();
- if (pid == -1 || !isAudioServerOrMediaServerUid(callingUid)) {
+ adjIdentity.uid = VALUE_OR_RETURN_STATUS(legacy2aidl_uid_t_int32_t(callingUid));
+ pid_t currentPid = VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_pid_t(adjIdentity.pid));
+ if (currentPid == -1 || !isAudioServerOrMediaServerUid(callingUid)) {
const pid_t callingPid = IPCThreadState::self()->getCallingPid();
- ALOGW_IF(pid != -1 && pid != callingPid,
+ ALOGW_IF(currentPid != -1 && currentPid != callingPid,
"%s uid %d pid %d tried to pass itself off as pid %d",
- __func__, callingUid, callingPid, pid);
- pid = callingPid;
+ __func__, callingUid, callingPid, currentPid);
+ adjIdentity.pid = VALUE_OR_RETURN_STATUS(legacy2aidl_pid_t_int32_t(callingPid));
+ currentPid = callingPid;
}
ALOGV("createEffect pid %d, effectClient %p, priority %d, sessionId %d, io %d, factory %p",
- pid, effectClient.get(), priority, sessionId, io, mEffectsFactoryHal.get());
+ adjIdentity.pid, effectClient.get(), priority, sessionId, io, mEffectsFactoryHal.get());
if (mEffectsFactoryHal == 0) {
ALOGE("%s: no effects factory hal", __func__);
@@ -3586,7 +3582,7 @@
goto Exit;
}
} else if (sessionId == AUDIO_SESSION_DEVICE) {
- if (!modifyDefaultAudioEffectsAllowed(pid, callingUid)) {
+ if (!modifyDefaultAudioEffectsAllowed(adjIdentity)) {
ALOGE("%s: device effect permission denied for uid %d", __func__, callingUid);
lStatus = PERMISSION_DENIED;
goto Exit;
@@ -3631,7 +3627,7 @@
// check recording permission for visualizer
if ((memcmp(&descOut.type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0) &&
// TODO: Do we need to start/stop op - i.e. is there recording being performed?
- !recordingAllowed(opPackageName, pid, callingUid)) {
+ !recordingAllowed(adjIdentity)) {
lStatus = PERMISSION_DENIED;
goto Exit;
}
@@ -3657,7 +3653,7 @@
Mutex::Autolock _l(mLock);
if (sessionId == AUDIO_SESSION_DEVICE) {
- sp<Client> client = registerPid(pid);
+ sp<Client> client = registerPid(currentPid);
ALOGV("%s device type %#x address %s", __func__, device.mType, device.getAddress());
handle = mDeviceEffectManager.createEffect_l(
&descOut, device, client, effectClient, mPatchPanel.patches_l(),
@@ -3761,7 +3757,7 @@
}
}
- sp<Client> client = registerPid(pid);
+ sp<Client> client = registerPid(currentPid);
// create effect on selected output thread
bool pinned = !audio_is_global_session(sessionId) && isSessionAcquired_l(sessionId);
diff --git a/services/audioflinger/MmapTracks.h b/services/audioflinger/MmapTracks.h
index b83f6b5..ba868d7 100644
--- a/services/audioflinger/MmapTracks.h
+++ b/services/audioflinger/MmapTracks.h
@@ -29,8 +29,7 @@
audio_channel_mask_t channelMask,
audio_session_t sessionId,
bool isOut,
- uid_t uid,
- pid_t pid,
+ const media::permission::Identity& identity,
pid_t creatorPid,
audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE);
virtual ~MmapTrack();
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index c70d6f9..a5b3077 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -15,6 +15,8 @@
** limitations under the License.
*/
+#include <android/media/permission/Identity.h>
+
#ifndef INCLUDING_FROM_AUDIOFLINGER_H
#error This header file should only be included from AudioFlinger.h
#endif
@@ -26,11 +28,13 @@
bool hasOpPlayAudio() const;
static sp<OpPlayAudioMonitor> createIfNeeded(
- uid_t uid, const audio_attributes_t& attr, int id, audio_stream_type_t streamType,
- const std::string& opPackageName);
+ const android::media::permission::Identity& identity,
+ const audio_attributes_t& attr, int id,
+ audio_stream_type_t streamType);
private:
- OpPlayAudioMonitor(uid_t uid, audio_usage_t usage, int id, const String16& opPackageName);
+ OpPlayAudioMonitor(const android::media::permission::Identity& identity,
+ audio_usage_t usage, int id);
void onFirstRef() override;
static void getPackagesForUid(uid_t uid, Vector<String16>& packages);
@@ -50,10 +54,9 @@
void checkPlayAudioForUsage();
std::atomic_bool mHasOpPlayAudio;
- const uid_t mUid;
+ const android::media::permission::Identity mIdentity;
const int32_t mUsage; // on purpose not audio_usage_t because always checked in appOps as int32_t
const int mId; // for logging purposes only
- const String16 mOpPackageName;
};
// playback track
@@ -72,14 +75,13 @@
const sp<IMemory>& sharedBuffer,
audio_session_t sessionId,
pid_t creatorPid,
- uid_t uid,
+ const media::permission::Identity& identity,
audio_output_flags_t flags,
track_type type,
audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE,
/** default behaviour is to start when there are as many frames
* ready as possible (aka. Buffer is full). */
- size_t frameCountToBeReady = SIZE_MAX,
- const std::string opPackageName = "");
+ size_t frameCountToBeReady = SIZE_MAX);
virtual ~Track();
virtual status_t initCheck() const;
@@ -336,7 +338,7 @@
audio_format_t format,
audio_channel_mask_t channelMask,
size_t frameCount,
- uid_t uid);
+ android::media::permission::Identity& identity);
virtual ~OutputTrack();
virtual status_t start(AudioSystem::sync_event_t event =
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index d87239d..4d03441 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -26,10 +26,10 @@
bool hasOpRecordAudio() const;
static sp<OpRecordAudioMonitor> createIfNeeded
- (uid_t uid, const audio_attributes_t& attr, const String16& opPackageName);
+ (const media::permission::Identity& identity, const audio_attributes_t& attr);
private:
- OpRecordAudioMonitor(uid_t uid, const String16& opPackageName);
+ explicit OpRecordAudioMonitor(const media::permission::Identity& identity);
void onFirstRef() override;
AppOpsManager mAppOpsManager;
@@ -49,8 +49,7 @@
void checkRecordAudio();
std::atomic_bool mHasOpRecordAudio;
- const uid_t mUid;
- const String16 mPackage;
+ const media::permission::Identity mIdentity;
};
// record track
@@ -67,10 +66,9 @@
size_t bufferSize,
audio_session_t sessionId,
pid_t creatorPid,
- uid_t uid,
+ const media::permission::Identity& identity,
audio_input_flags_t flags,
track_type type,
- const String16& opPackageName,
audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE);
virtual ~RecordTrack();
virtual status_t initCheck() const;
@@ -149,7 +147,7 @@
// used to enforce OP_RECORD_AUDIO
uid_t mUid;
- String16 mOpPackageName;
+ media::permission::Identity mIdentity;
sp<OpRecordAudioMonitor> mOpRecordAudioMonitor;
};
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index eaf0d10..90f7a61 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -108,6 +108,7 @@
// TODO: Move these macro/inlines to a header file.
#define max(a, b) ((a) > (b) ? (a) : (b))
+
template <typename T>
static inline T min(const T& a, const T& b)
{
@@ -117,6 +118,7 @@
namespace android {
using media::IEffectClient;
+using media::permission::Identity;
// retry counts for buffer fill timeout
// 50 * ~20msecs = 1 second
@@ -2076,12 +2078,11 @@
audio_session_t sessionId,
audio_output_flags_t *flags,
pid_t creatorPid,
+ const Identity& identity,
pid_t tid,
- uid_t uid,
status_t *status,
audio_port_handle_t portId,
- const sp<media::IAudioTrackCallback>& callback,
- const std::string& opPackageName)
+ const sp<media::IAudioTrackCallback>& callback)
{
size_t frameCount = *pFrameCount;
size_t notificationFrameCount = *pNotificationFrameCount;
@@ -2172,8 +2173,8 @@
"sampleRate=%u mSampleRate=%u "
"hasFastMixer=%d tid=%d fastTrackAvailMask=%#x",
sharedBuffer.get(), frameCount, mFrameCount, format, mFormat,
- audio_is_linear_pcm(format),
- channelMask, sampleRate, mSampleRate, hasFastMixer(), tid, mFastTrackAvailMask);
+ audio_is_linear_pcm(format), channelMask, sampleRate,
+ mSampleRate, hasFastMixer(), tid, mFastTrackAvailMask);
*flags = (audio_output_flags_t)(*flags & ~AUDIO_OUTPUT_FLAG_FAST);
}
}
@@ -2372,8 +2373,8 @@
track = new Track(this, client, streamType, attr, sampleRate, format,
channelMask, frameCount,
nullptr /* buffer */, (size_t)0 /* bufferSize */, sharedBuffer,
- sessionId, creatorPid, uid, trackFlags, TrackBase::TYPE_DEFAULT, portId,
- SIZE_MAX /*frameCountToBeReady*/, opPackageName);
+ sessionId, creatorPid, identity, trackFlags, TrackBase::TYPE_DEFAULT,
+ portId, SIZE_MAX /*frameCountToBeReady*/);
lStatus = track != 0 ? track->initCheck() : (status_t) NO_MEMORY;
if (lStatus != NO_ERROR) {
@@ -6812,13 +6813,19 @@
// from different OutputTracks and their associated MixerThreads (e.g. one may
// nearly empty and the other may be dropping data).
+ // TODO b/182392769: use identity util, move to server edge
+ Identity identity = Identity();
+ identity.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(
+ IPCThreadState::self()->getCallingUid()));
+ identity.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(
+ IPCThreadState::self()->getCallingPid()));
sp<OutputTrack> outputTrack = new OutputTrack(thread,
this,
mSampleRate,
mFormat,
mChannelMask,
frameCount,
- IPCThreadState::self()->getCallingUid());
+ identity);
status_t status = outputTrack != 0 ? outputTrack->initCheck() : (status_t) NO_MEMORY;
if (status != NO_ERROR) {
ALOGE("addOutputTrack() initCheck failed %d", status);
@@ -7730,12 +7737,11 @@
audio_session_t sessionId,
size_t *pNotificationFrameCount,
pid_t creatorPid,
- uid_t uid,
+ const Identity& identity,
audio_input_flags_t *flags,
pid_t tid,
status_t *status,
- audio_port_handle_t portId,
- const String16& opPackageName)
+ audio_port_handle_t portId)
{
size_t frameCount = *pFrameCount;
size_t notificationFrameCount = *pNotificationFrameCount;
@@ -7868,8 +7874,8 @@
track = new RecordTrack(this, client, attr, sampleRate,
format, channelMask, frameCount,
- nullptr /* buffer */, (size_t)0 /* bufferSize */, sessionId, creatorPid, uid,
- *flags, TrackBase::TYPE_DEFAULT, opPackageName, portId);
+ nullptr /* buffer */, (size_t)0 /* bufferSize */, sessionId, creatorPid,
+ identity, *flags, TrackBase::TYPE_DEFAULT, portId);
lStatus = track->initCheck();
if (lStatus != NO_ERROR) {
@@ -8884,7 +8890,7 @@
audio_port_handle_t *handle)
{
ALOGV("%s clientUid %d mStandby %d mPortId %d *handle %d", __FUNCTION__,
- client.clientUid, mStandby, mPortId, *handle);
+ client.identity.uid, mStandby, mPortId, *handle);
if (mHalStream == 0) {
return NO_INIT;
}
@@ -8916,8 +8922,7 @@
ret = AudioSystem::getOutputForAttr(&mAttr, &io,
mSessionId,
&stream,
- client.clientPid,
- client.clientUid,
+ client.identity,
&config,
flags,
&deviceId,
@@ -8934,9 +8939,7 @@
ret = AudioSystem::getInputForAttr(&mAttr, &io,
RECORD_RIID_INVALID,
mSessionId,
- client.clientPid,
- client.clientUid,
- client.packageName,
+ client.identity,
&config,
AUDIO_INPUT_FLAG_MMAP_NOIRQ,
&deviceId,
@@ -8976,16 +8979,15 @@
// Given that MmapThread::mAttr is mutable, should a MmapTrack have attributes ?
sp<MmapTrack> track = new MmapTrack(this, attr == nullptr ? mAttr : *attr, mSampleRate, mFormat,
- mChannelMask, mSessionId, isOutput(), client.clientUid,
- client.clientPid, IPCThreadState::self()->getCallingPid(),
- portId);
+ mChannelMask, mSessionId, isOutput(), client.identity,
+ IPCThreadState::self()->getCallingPid(), portId);
if (isOutput()) {
// force volume update when a new track is added
mHalVolFloat = -1.0f;
} else if (!track->isSilenced_l()) {
for (const sp<MmapTrack> &t : mActiveTracks) {
- if (t->isSilenced_l() && t->uid() != client.clientUid)
+ if (t->isSilenced_l() && t->uid() != client.identity.uid)
t->invalidate();
}
}
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index c974252..5aa5169 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -882,12 +882,11 @@
audio_session_t sessionId,
audio_output_flags_t *flags,
pid_t creatorPid,
+ const media::permission::Identity& identity,
pid_t tid,
- uid_t uid,
status_t *status /*non-NULL*/,
audio_port_handle_t portId,
- const sp<media::IAudioTrackCallback>& callback,
- const std::string& opPackageName);
+ const sp<media::IAudioTrackCallback>& callback);
AudioStreamOut* getOutput() const;
AudioStreamOut* clearOutput();
@@ -1642,12 +1641,11 @@
audio_session_t sessionId,
size_t *pNotificationFrameCount,
pid_t creatorPid,
- uid_t uid,
+ const media::permission::Identity& identity,
audio_input_flags_t *flags,
pid_t tid,
status_t *status /*non-NULL*/,
- audio_port_handle_t portId,
- const String16& opPackageName);
+ audio_port_handle_t portId);
status_t start(RecordTrack* recordTrack,
AudioSystem::sync_event_t event,
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 5454778..a86102f 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -65,6 +65,7 @@
using ::android::aidl_utils::binderStatusFromStatusT;
using binder::Status;
+using media::permission::Identity;
using media::VolumeShaper;
// ----------------------------------------------------------------------------
// TrackBase
@@ -237,6 +238,13 @@
}
}
+// TODO b/182392769: use identity util
+Identity audioServerIdentity() {
+ Identity i = Identity();
+ i.uid = AID_AUDIOSERVER;
+ return i;
+}
+
status_t AudioFlinger::ThreadBase::TrackBase::initCheck() const
{
status_t status;
@@ -489,10 +497,11 @@
// static
sp<AudioFlinger::PlaybackThread::OpPlayAudioMonitor>
AudioFlinger::PlaybackThread::OpPlayAudioMonitor::createIfNeeded(
- uid_t uid, const audio_attributes_t& attr, int id, audio_stream_type_t streamType,
- const std::string& opPackageName)
+ const Identity& identity, const audio_attributes_t& attr, int id,
+ audio_stream_type_t streamType)
{
Vector <String16> packages;
+ uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.uid));
getPackagesForUid(uid, packages);
if (isServiceUid(uid)) {
if (packages.isEmpty()) {
@@ -515,31 +524,36 @@
return nullptr;
}
- String16 opPackageNameStr(opPackageName.c_str());
- if (opPackageName.empty()) {
+ // TODO b/182392769: use identity util
+ std::optional<std::string> opPackageNameStr = identity.packageName;
+ if (!identity.packageName.has_value()) {
// If no package name is provided by the client, use the first associated with the uid
if (!packages.isEmpty()) {
- opPackageNameStr = packages[0];
+ opPackageNameStr =
+ VALUE_OR_FATAL(legacy2aidl_String16_string(packages[0]));
}
} else {
// If the provided package name is invalid, we force app ops denial by clearing the package
// name passed to OpPlayAudioMonitor
+ String16 opPackageLegacy = VALUE_OR_FATAL(
+ aidl2legacy_string_view_String16(opPackageNameStr.value_or("")));
if (std::find_if(packages.begin(), packages.end(),
- [&opPackageNameStr](const auto& package) {
- return opPackageNameStr == package; }) == packages.end()) {
+ [&opPackageLegacy](const auto& package) {
+ return opPackageLegacy == package; }) == packages.end()) {
ALOGW("The package name(%s) provided does not correspond to the uid %d, "
- "force muting the track", opPackageName.c_str(), uid);
- // Set package name as an empty string so that hasOpPlayAudio will always return false.
- opPackageNameStr = String16("");
+ "force muting the track", opPackageNameStr.value().c_str(), uid);
+ // Set null package name so hasOpPlayAudio will always return false.
+ opPackageNameStr = std::optional<std::string>();
}
}
- return new OpPlayAudioMonitor(uid, attr.usage, id, opPackageNameStr);
+ Identity adjIdentity = identity;
+ adjIdentity.packageName = opPackageNameStr;
+ return new OpPlayAudioMonitor(adjIdentity, attr.usage, id);
}
AudioFlinger::PlaybackThread::OpPlayAudioMonitor::OpPlayAudioMonitor(
- uid_t uid, audio_usage_t usage, int id, const String16& opPackageName)
- : mHasOpPlayAudio(true), mUid(uid), mUsage((int32_t) usage), mId(id),
- mOpPackageName(opPackageName)
+ const Identity& identity, audio_usage_t usage, int id)
+ : mHasOpPlayAudio(true), mIdentity(identity), mUsage((int32_t) usage), mId(id)
{
}
@@ -554,9 +568,11 @@
void AudioFlinger::PlaybackThread::OpPlayAudioMonitor::onFirstRef()
{
checkPlayAudioForUsage();
- if (mOpPackageName.size() != 0) {
+ if (mIdentity.packageName.has_value()) {
mOpCallback = new PlayAudioOpCallback(this);
- mAppOpsManager.startWatchingMode(AppOpsManager::OP_PLAY_AUDIO, mOpPackageName, mOpCallback);
+ mAppOpsManager.startWatchingMode(AppOpsManager::OP_PLAY_AUDIO,
+ VALUE_OR_FATAL(aidl2legacy_string_view_String16(mIdentity.packageName.value_or("")))
+ , mOpCallback);
}
}
@@ -569,11 +585,14 @@
// - not called from PlayAudioOpCallback because the callback is not installed in this case
void AudioFlinger::PlaybackThread::OpPlayAudioMonitor::checkPlayAudioForUsage()
{
- if (mOpPackageName.size() == 0) {
+ if (!mIdentity.packageName.has_value()) {
mHasOpPlayAudio.store(false);
} else {
+ uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(mIdentity.uid));
+ String16 packageName = VALUE_OR_FATAL(
+ aidl2legacy_string_view_String16(mIdentity.packageName.value_or("")));
bool hasIt = mAppOpsManager.checkAudioOpNoThrow(AppOpsManager::OP_PLAY_AUDIO,
- mUsage, mUid, mOpPackageName) == AppOpsManager::MODE_ALLOWED;
+ mUsage, uid, packageName) == AppOpsManager::MODE_ALLOWED;
ALOGD("OpPlayAudio: track:%d usage:%d %smuted", mId, mUsage, hasIt ? "not " : "");
mHasOpPlayAudio.store(hasIt);
}
@@ -623,12 +642,11 @@
const sp<IMemory>& sharedBuffer,
audio_session_t sessionId,
pid_t creatorPid,
- uid_t uid,
+ const Identity& identity,
audio_output_flags_t flags,
track_type type,
audio_port_handle_t portId,
- size_t frameCountToBeReady,
- const std::string opPackageName)
+ size_t frameCountToBeReady)
: TrackBase(thread, client, attr, sampleRate, format, channelMask, frameCount,
// TODO: Using unsecurePointer() has some associated security pitfalls
// (see declaration for details).
@@ -636,7 +654,8 @@
// issue (e.g. by copying).
(sharedBuffer != 0) ? sharedBuffer->unsecurePointer() : buffer,
(sharedBuffer != 0) ? sharedBuffer->size() : bufferSize,
- sessionId, creatorPid, uid, true /*isOut*/,
+ sessionId, creatorPid,
+ VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.uid)), true /*isOut*/,
(type == TYPE_PATCH) ? ( buffer == NULL ? ALLOC_LOCAL : ALLOC_NONE) : ALLOC_CBLK,
type,
portId,
@@ -651,8 +670,8 @@
mPresentationCompleteFrames(0),
mFrameMap(16 /* sink-frame-to-track-frame map memory */),
mVolumeHandler(new media::VolumeHandler(sampleRate)),
- mOpPlayAudioMonitor(OpPlayAudioMonitor::createIfNeeded(
- uid, attr, id(), streamType, opPackageName)),
+ mOpPlayAudioMonitor(OpPlayAudioMonitor::createIfNeeded(identity, attr, id(),
+ streamType)),
// mSinkTimestamp
mFrameCountToBeReady(frameCountToBeReady),
mFastIndex(-1),
@@ -674,6 +693,7 @@
return;
}
+ uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.uid));
if (!thread->isTrackAllowed_l(channelMask, format, sessionId, uid)) {
ALOGE("%s(%d): no more tracks available", __func__, mId);
releaseCblk(); // this makes the track invalid.
@@ -718,8 +738,10 @@
// HapticGenerator effect, which will generate haptic data, on the track. In that case,
// external vibration is always created for all tracks attached to haptic playback thread.
mAudioVibrationController = new AudioVibrationController(this);
+ std::string packageName = identity.packageName.has_value() ?
+ identity.packageName.value() : "";
mExternalVibration = new os::ExternalVibration(
- mUid, opPackageName, mAttr, mAudioVibrationController);
+ mUid, packageName, mAttr, mAudioVibrationController);
}
// Once this item is logged by the server, the client can add properties.
@@ -1821,12 +1843,12 @@
audio_format_t format,
audio_channel_mask_t channelMask,
size_t frameCount,
- uid_t uid)
+ Identity& identity)
: Track(playbackThread, NULL, AUDIO_STREAM_PATCH,
audio_attributes_t{} /* currently unused for output track */,
sampleRate, format, channelMask, frameCount,
nullptr /* buffer */, (size_t)0 /* bufferSize */, nullptr /* sharedBuffer */,
- AUDIO_SESSION_NONE, getpid(), uid, AUDIO_OUTPUT_FLAG_NONE,
+ AUDIO_SESSION_NONE, getpid(), identity, AUDIO_OUTPUT_FLAG_NONE,
TYPE_OUTPUT),
mActive(false), mSourceThread(sourceThread)
{
@@ -2056,8 +2078,8 @@
audio_attributes_t{} /* currently unused for patch track */,
sampleRate, format, channelMask, frameCount,
buffer, bufferSize, nullptr /* sharedBuffer */,
- AUDIO_SESSION_NONE, getpid(), AID_AUDIOSERVER, flags, TYPE_PATCH,
- AUDIO_PORT_HANDLE_NONE, frameCountToBeReady),
+ AUDIO_SESSION_NONE, getpid(), audioServerIdentity(), flags,
+ TYPE_PATCH, AUDIO_PORT_HANDLE_NONE, frameCountToBeReady),
PatchTrackBase(new ClientProxy(mCblk, mBuffer, frameCount, mFrameSize, true, true),
*playbackThread, timeout)
{
@@ -2194,41 +2216,44 @@
// static
sp<AudioFlinger::RecordThread::OpRecordAudioMonitor>
AudioFlinger::RecordThread::OpRecordAudioMonitor::createIfNeeded(
- uid_t uid, const audio_attributes_t& attr, const String16& opPackageName)
+ const Identity& identity, const audio_attributes_t& attr)
{
- if (isServiceUid(uid)) {
- ALOGV("not silencing record for service uid:%d pack:%s",
- uid, String8(opPackageName).string());
+ if (isServiceUid(identity.uid)) {
+ ALOGV("not silencing record for service %s",
+ identity.toString().c_str());
return nullptr;
}
// Capturing from FM TUNER output is not controlled by OP_RECORD_AUDIO
// because it does not affect users privacy as does capturing from an actual microphone.
if (attr.source == AUDIO_SOURCE_FM_TUNER) {
- ALOGV("not muting FM TUNER capture for uid %d", uid);
+ ALOGV("not muting FM TUNER capture for uid %d", identity.uid);
return nullptr;
}
- if (opPackageName.size() == 0) {
+ if (!identity.packageName.has_value() || identity.packageName.value().size() == 0) {
Vector<String16> packages;
// no package name, happens with SL ES clients
// query package manager to find one
PermissionController permissionController;
- permissionController.getPackagesForUid(uid, packages);
+ permissionController.getPackagesForUid(identity.uid, packages);
if (packages.isEmpty()) {
return nullptr;
} else {
- ALOGV("using pack:%s for uid:%d", String8(packages[0]).string(), uid);
- return new OpRecordAudioMonitor(uid, packages[0]);
+ Identity adjIdentity = identity;
+ adjIdentity.packageName =
+ VALUE_OR_FATAL(legacy2aidl_String16_string(packages[0]));
+ ALOGV("using identity:%s", adjIdentity.toString().c_str());
+ return new OpRecordAudioMonitor(adjIdentity);
}
}
- return new OpRecordAudioMonitor(uid, opPackageName);
+ return new OpRecordAudioMonitor(identity);
}
AudioFlinger::RecordThread::OpRecordAudioMonitor::OpRecordAudioMonitor(
- uid_t uid, const String16& opPackageName)
- : mHasOpRecordAudio(true), mUid(uid), mPackage(opPackageName)
+ const Identity& identity)
+ : mHasOpRecordAudio(true), mIdentity(identity)
{
}
@@ -2244,8 +2269,10 @@
{
checkRecordAudio();
mOpCallback = new RecordAudioOpCallback(this);
- ALOGV("start watching OP_RECORD_AUDIO for pack:%s", String8(mPackage).string());
- mAppOpsManager.startWatchingMode(AppOpsManager::OP_RECORD_AUDIO, mPackage, mOpCallback);
+ ALOGV("start watching OP_RECORD_AUDIO for %s", mIdentity.toString().c_str());
+ mAppOpsManager.startWatchingMode(AppOpsManager::OP_RECORD_AUDIO,
+ VALUE_OR_FATAL(aidl2legacy_string_view_String16(mIdentity.packageName.value_or(""))),
+ mOpCallback);
}
bool AudioFlinger::RecordThread::OpRecordAudioMonitor::hasOpRecordAudio() const {
@@ -2260,14 +2287,17 @@
// - not called from RecordAudioOpCallback because the callback is not installed in this case
void AudioFlinger::RecordThread::OpRecordAudioMonitor::checkRecordAudio()
{
+
const int32_t mode = mAppOpsManager.checkOp(AppOpsManager::OP_RECORD_AUDIO,
- mUid, mPackage);
+ mIdentity.uid, VALUE_OR_FATAL(aidl2legacy_string_view_String16(
+ mIdentity.packageName.value_or(""))));
const bool hasIt = (mode == AppOpsManager::MODE_ALLOWED);
// verbose logging only log when appOp changed
ALOGI_IF(hasIt != mHasOpRecordAudio.load(),
- "OP_RECORD_AUDIO missing, %ssilencing record uid%d pack:%s",
- hasIt ? "un" : "", mUid, String8(mPackage).string());
+ "OP_RECORD_AUDIO missing, %ssilencing record %s",
+ hasIt ? "un" : "", mIdentity.toString().c_str());
mHasOpRecordAudio.store(hasIt);
+
}
AudioFlinger::RecordThread::OpRecordAudioMonitor::RecordAudioOpCallback::RecordAudioOpCallback(
@@ -2361,14 +2391,15 @@
size_t bufferSize,
audio_session_t sessionId,
pid_t creatorPid,
- uid_t uid,
+ const Identity& identity,
audio_input_flags_t flags,
track_type type,
- const String16& opPackageName,
audio_port_handle_t portId)
: TrackBase(thread, client, attr, sampleRate, format,
channelMask, frameCount, buffer, bufferSize, sessionId,
- creatorPid, uid, false /*isOut*/,
+ creatorPid,
+ VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.uid)),
+ false /*isOut*/,
(type == TYPE_DEFAULT) ?
((flags & AUDIO_INPUT_FLAG_FAST) ? ALLOC_PIPE : ALLOC_CBLK) :
((buffer == NULL) ? ALLOC_LOCAL : ALLOC_NONE),
@@ -2380,7 +2411,7 @@
mRecordBufferConverter(NULL),
mFlags(flags),
mSilenced(false),
- mOpRecordAudioMonitor(OpRecordAudioMonitor::createIfNeeded(uid, attr, opPackageName))
+ mOpRecordAudioMonitor(OpRecordAudioMonitor::createIfNeeded(mIdentity, attr))
{
if (mCblk == NULL) {
return;
@@ -2421,7 +2452,9 @@
#endif
// Once this item is logged by the server, the client can add properties.
- mTrackMetrics.logConstructor(creatorPid, uid, id());
+ pid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(mIdentity.pid));
+ uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(mIdentity.uid));
+ mTrackMetrics.logConstructor(pid, uid, id());
}
AudioFlinger::RecordThread::RecordTrack::~RecordTrack()
@@ -2692,11 +2725,12 @@
: RecordTrack(recordThread, NULL,
audio_attributes_t{} /* currently unused for patch track */,
sampleRate, format, channelMask, frameCount,
- buffer, bufferSize, AUDIO_SESSION_NONE, getpid(), AID_AUDIOSERVER,
- flags, TYPE_PATCH, String16()),
+ buffer, bufferSize, AUDIO_SESSION_NONE, getpid(),
+ audioServerIdentity(), flags, TYPE_PATCH),
PatchTrackBase(new ClientProxy(mCblk, mBuffer, frameCount, mFrameSize, false, true),
*recordThread, timeout)
{
+ mIdentity.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(getpid()));
ALOGV("%s(%d): sampleRate %d mPeerTimeout %d.%03d sec",
__func__, mId, sampleRate,
(int)mPeerTimeout.tv_sec,
@@ -2970,21 +3004,24 @@
audio_channel_mask_t channelMask,
audio_session_t sessionId,
bool isOut,
- uid_t uid,
- pid_t pid,
+ const Identity& identity,
pid_t creatorPid,
audio_port_handle_t portId)
: TrackBase(thread, NULL, attr, sampleRate, format,
channelMask, (size_t)0 /* frameCount */,
nullptr /* buffer */, (size_t)0 /* bufferSize */,
- sessionId, creatorPid, uid, isOut,
+ sessionId, creatorPid,
+ VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.uid)),
+ isOut,
ALLOC_NONE,
TYPE_DEFAULT, portId,
std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_MMAP) + std::to_string(portId)),
- mPid(pid), mSilenced(false), mSilencedNotified(false)
+ mPid(VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.pid))),
+ mSilenced(false), mSilencedNotified(false)
{
// Once this item is logged by the server, the client can add properties.
- mTrackMetrics.logConstructor(creatorPid, uid, id());
+ mTrackMetrics.logConstructor(creatorPid,
+ VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(identity.uid)), id());
}
AudioFlinger::MmapThread::MmapTrack::~MmapTrack()
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 9132086..5f052a5 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -21,6 +21,7 @@
#include <media/AudioSystem.h>
#include <media/AudioPolicy.h>
#include <media/DeviceDescriptorBase.h>
+#include <android/media/permission/Identity.h>
#include <utils/String8.h>
namespace android {
@@ -122,7 +123,7 @@
audio_io_handle_t *output,
audio_session_t session,
audio_stream_type_t *stream,
- uid_t uid,
+ const media::permission::Identity& identity,
const audio_config_t *config,
audio_output_flags_t *flags,
audio_port_handle_t *selectedDeviceId,
@@ -141,7 +142,7 @@
audio_io_handle_t *input,
audio_unique_id_t riid,
audio_session_t session,
- uid_t uid,
+ const media::permission::Identity& identity,
const audio_config_base_t *config,
audio_input_flags_t flags,
audio_port_handle_t *selectedDeviceId,
@@ -272,8 +273,11 @@
virtual status_t getSurroundFormats(unsigned int *numSurroundFormats,
audio_format_t *surroundFormats,
- bool *surroundFormatsEnabled,
- bool reported) = 0;
+ bool *surroundFormatsEnabled) = 0;
+
+ virtual status_t getReportedSurroundFormats(unsigned int *numSurroundFormats,
+ audio_format_t *surroundFormats) = 0;
+
virtual status_t setSurroundFormatEnabled(audio_format_t audioFormat, bool enabled) = 0;
virtual bool isHapticPlaybackSupported() = 0;
diff --git a/services/audiopolicy/common/managerdefinitions/include/Serializer.h b/services/audiopolicy/common/managerdefinitions/include/Serializer.h
index 48c4147..b70c595 100644
--- a/services/audiopolicy/common/managerdefinitions/include/Serializer.h
+++ b/services/audiopolicy/common/managerdefinitions/include/Serializer.h
@@ -21,5 +21,9 @@
namespace android {
status_t deserializeAudioPolicyFile(const char *fileName, AudioPolicyConfig *config);
+// In VTS mode all vendor extensions are ignored. This is done because
+// VTS tests are built using AOSP code and thus can not use vendor overlays
+// of system libraries.
+status_t deserializeAudioPolicyFileForVts(const char *fileName, AudioPolicyConfig *config);
} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
index 129f6f6..562c213 100644
--- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
@@ -20,8 +20,8 @@
#include <memory>
#include <string>
#include <utility>
+#include <variant>
-#include <hidl/Status.h>
#include <libxml/parser.h>
#include <libxml/xinclude.h>
#include <media/convert.h>
@@ -36,12 +36,14 @@
namespace {
-// TODO(mnaganov): Consider finding an alternative for using HIDL code.
-using hardware::Return;
-using hardware::Status;
-using hardware::Void;
using utilities::convertTo;
+static inline bool maybeVendorExtension(const std::string& s) {
+ // Only checks whether the string starts with the "vendor prefix".
+ static const std::string vendorPrefix = "VX_";
+ return s.size() > vendorPrefix.size() && s.substr(0, vendorPrefix.size()) == vendorPrefix;
+}
+
template<typename E, typename C>
struct AndroidCollectionTraits {
typedef sp<E> Element;
@@ -187,7 +189,7 @@
struct GlobalConfigTraits
{
- typedef void Element;
+ typedef std::monostate Element;
static constexpr const char *tag = "globalConfiguration";
@@ -203,7 +205,7 @@
struct SurroundSoundTraits
{
- typedef void Element;
+ typedef std::monostate Element;
static constexpr const char *tag = "surroundSound";
@@ -226,14 +228,15 @@
class PolicySerializer
{
public:
- status_t deserialize(const char *configFile, AudioPolicyConfig *config);
+ status_t deserialize(const char *configFile, AudioPolicyConfig *config,
+ bool ignoreVendorExtensions = false);
template <class Trait>
status_t deserializeCollection(const xmlNode *cur,
typename Trait::Collection *collection,
typename Trait::PtrSerializingCtx serializingContext);
template <class Trait>
- Return<typename Trait::Element> deserialize(const xmlNode *cur,
+ std::variant<status_t, typename Trait::Element> deserialize(const xmlNode *cur,
typename Trait::PtrSerializingCtx serializingContext);
private:
@@ -242,6 +245,7 @@
typedef AudioPolicyConfig Element;
+ bool mIgnoreVendorExtensions = false;
std::string mChannelMasksSeparator = ",";
std::string mSamplingRatesSeparator = ",";
std::string mFlagsSeparator = "|";
@@ -307,14 +311,17 @@
}
for (; child != NULL; child = child->next) {
if (!xmlStrcmp(child->name, reinterpret_cast<const xmlChar*>(Trait::tag))) {
- auto element = deserialize<Trait>(child, serializingContext);
- if (element.isOk()) {
- status_t status = Trait::addElementToCollection(element, collection);
+ auto maybeElement = deserialize<Trait>(child, serializingContext);
+ if (maybeElement.index() == 1) {
+ status_t status = Trait::addElementToCollection(
+ std::get<1>(maybeElement), collection);
if (status != NO_ERROR) {
ALOGE("%s: could not add element to %s collection", __func__,
Trait::collectionTag);
return status;
}
+ } else if (mIgnoreVendorExtensions && std::get<status_t>(maybeElement) == NO_INIT) {
+ // Skip a vendor extension element.
} else {
return BAD_VALUE;
}
@@ -328,8 +335,8 @@
}
template<>
-Return<AudioGainTraits::Element> PolicySerializer::deserialize<AudioGainTraits>(const xmlNode *cur,
- AudioGainTraits::PtrSerializingCtx /*serializingContext*/)
+std::variant<status_t, AudioGainTraits::Element> PolicySerializer::deserialize<AudioGainTraits>(
+ const xmlNode *cur, AudioGainTraits::PtrSerializingCtx /*serializingContext*/)
{
using Attributes = AudioGainTraits::Attributes;
@@ -393,12 +400,13 @@
if (gain->getMode() != 0) {
return gain;
} else {
- return Status::fromStatusT(BAD_VALUE);
+ return BAD_VALUE;
}
}
template<>
-Return<AudioProfileTraits::Element> PolicySerializer::deserialize<AudioProfileTraits>(
+std::variant<status_t, AudioProfileTraits::Element>
+PolicySerializer::deserialize<AudioProfileTraits>(
const xmlNode *cur, AudioProfileTraits::PtrSerializingCtx /*serializingContext*/)
{
using Attributes = AudioProfileTraits::Attributes;
@@ -407,6 +415,10 @@
std::string format = getXmlAttribute(cur, Attributes::format);
std::string channels = getXmlAttribute(cur, Attributes::channelMasks);
+ if (mIgnoreVendorExtensions && maybeVendorExtension(format)) {
+ ALOGI("%s: vendor extension format \"%s\" skipped", __func__, format.c_str());
+ return NO_INIT;
+ }
AudioProfileTraits::Element profile = new AudioProfile(formatFromString(format, gDynamicFormat),
channelMasksFromString(channels, mChannelMasksSeparator.c_str()),
samplingRatesFromString(samplingRates, mSamplingRatesSeparator.c_str()));
@@ -419,21 +431,21 @@
}
template<>
-Return<MixPortTraits::Element> PolicySerializer::deserialize<MixPortTraits>(const xmlNode *child,
- MixPortTraits::PtrSerializingCtx /*serializingContext*/)
+std::variant<status_t, MixPortTraits::Element> PolicySerializer::deserialize<MixPortTraits>(
+ const xmlNode *child, MixPortTraits::PtrSerializingCtx /*serializingContext*/)
{
using Attributes = MixPortTraits::Attributes;
std::string name = getXmlAttribute(child, Attributes::name);
if (name.empty()) {
ALOGE("%s: No %s found", __func__, Attributes::name);
- return Status::fromStatusT(BAD_VALUE);
+ return BAD_VALUE;
}
ALOGV("%s: %s %s=%s", __func__, MixPortTraits::tag, Attributes::name, name.c_str());
std::string role = getXmlAttribute(child, Attributes::role);
if (role.empty()) {
ALOGE("%s: No %s found", __func__, Attributes::role);
- return Status::fromStatusT(BAD_VALUE);
+ return BAD_VALUE;
}
ALOGV("%s: Role=%s", __func__, role.c_str());
audio_port_role_t portRole = (role == Attributes::roleSource) ?
@@ -444,7 +456,7 @@
AudioProfileTraits::Collection profiles;
status_t status = deserializeCollection<AudioProfileTraits>(child, &profiles, NULL);
if (status != NO_ERROR) {
- return Status::fromStatusT(status);
+ return status;
}
if (profiles.empty()) {
profiles.add(AudioProfile::createFullDynamic(gDynamicFormat));
@@ -476,7 +488,7 @@
AudioGainTraits::Collection gains;
status = deserializeCollection<AudioGainTraits>(child, &gains, NULL);
if (status != NO_ERROR) {
- return Status::fromStatusT(status);
+ return status;
}
mixPort->setGains(gains);
@@ -484,7 +496,7 @@
}
template<>
-Return<DevicePortTraits::Element> PolicySerializer::deserialize<DevicePortTraits>(
+std::variant<status_t, DevicePortTraits::Element> PolicySerializer::deserialize<DevicePortTraits>(
const xmlNode *cur, DevicePortTraits::PtrSerializingCtx /*serializingContext*/)
{
using Attributes = DevicePortTraits::Attributes;
@@ -493,30 +505,34 @@
std::string name = getXmlAttribute(cur, Attributes::tagName);
if (name.empty()) {
ALOGE("%s: No %s found", __func__, Attributes::tagName);
- return Status::fromStatusT(BAD_VALUE);
+ return BAD_VALUE;
}
ALOGV("%s: %s %s=%s", __func__, tag, Attributes::tagName, name.c_str());
std::string typeName = getXmlAttribute(cur, Attributes::type);
if (typeName.empty()) {
ALOGE("%s: no type for %s", __func__, name.c_str());
- return Status::fromStatusT(BAD_VALUE);
+ return BAD_VALUE;
}
ALOGV("%s: %s %s=%s", __func__, tag, Attributes::type, typeName.c_str());
std::string role = getXmlAttribute(cur, Attributes::role);
if (role.empty()) {
ALOGE("%s: No %s found", __func__, Attributes::role);
- return Status::fromStatusT(BAD_VALUE);
+ return BAD_VALUE;
}
ALOGV("%s: %s %s=%s", __func__, tag, Attributes::role, role.c_str());
audio_port_role_t portRole = (role == Attributes::roleSource) ?
AUDIO_PORT_ROLE_SOURCE : AUDIO_PORT_ROLE_SINK;
+ if (mIgnoreVendorExtensions && maybeVendorExtension(typeName)) {
+ ALOGI("%s: vendor extension device type \"%s\" skipped", __func__, typeName.c_str());
+ return NO_INIT;
+ }
audio_devices_t type = AUDIO_DEVICE_NONE;
if (!DeviceConverter::fromString(typeName, type) ||
(!audio_is_input_device(type) && portRole == AUDIO_PORT_ROLE_SOURCE) ||
(!audio_is_output_devices(type) && portRole == AUDIO_PORT_ROLE_SINK)) {
ALOGW("%s: bad type %08x", __func__, type);
- return Status::fromStatusT(BAD_VALUE);
+ return BAD_VALUE;
}
std::string encodedFormatsLiteral = getXmlAttribute(cur, Attributes::encodedFormats);
ALOGV("%s: %s %s=%s", __func__, tag, Attributes::encodedFormats, encodedFormatsLiteral.c_str());
@@ -531,7 +547,7 @@
AudioProfileTraits::Collection profiles;
status_t status = deserializeCollection<AudioProfileTraits>(cur, &profiles, NULL);
if (status != NO_ERROR) {
- return Status::fromStatusT(status);
+ return status;
}
if (profiles.empty()) {
profiles.add(AudioProfile::createFullDynamic(gDynamicFormat));
@@ -544,7 +560,7 @@
// Deserialize AudioGain children
status = deserializeCollection<AudioGainTraits>(cur, &deviceDesc->mGains, NULL);
if (status != NO_ERROR) {
- return Status::fromStatusT(status);
+ return status;
}
ALOGV("%s: adding device tag %s type %08x address %s", __func__,
deviceDesc->getName().c_str(), type, deviceDesc->address().c_str());
@@ -552,7 +568,7 @@
}
template<>
-Return<RouteTraits::Element> PolicySerializer::deserialize<RouteTraits>(
+std::variant<status_t, RouteTraits::Element> PolicySerializer::deserialize<RouteTraits>(
const xmlNode *cur, RouteTraits::PtrSerializingCtx ctx)
{
using Attributes = RouteTraits::Attributes;
@@ -560,7 +576,7 @@
std::string type = getXmlAttribute(cur, Attributes::type);
if (type.empty()) {
ALOGE("%s: No %s found", __func__, Attributes::type);
- return Status::fromStatusT(BAD_VALUE);
+ return BAD_VALUE;
}
audio_route_type_t routeType = (type == Attributes::typeMix) ?
AUDIO_ROUTE_MIX : AUDIO_ROUTE_MUX;
@@ -571,20 +587,24 @@
std::string sinkAttr = getXmlAttribute(cur, Attributes::sink);
if (sinkAttr.empty()) {
ALOGE("%s: No %s found", __func__, Attributes::sink);
- return Status::fromStatusT(BAD_VALUE);
+ return BAD_VALUE;
}
// Convert Sink name to port pointer
sp<PolicyAudioPort> sink = ctx->findPortByTagName(sinkAttr);
- if (sink == NULL) {
+ if (sink == NULL && !mIgnoreVendorExtensions) {
ALOGE("%s: no sink found with name=%s", __func__, sinkAttr.c_str());
- return Status::fromStatusT(BAD_VALUE);
+ return BAD_VALUE;
+ } else if (sink == NULL) {
+ ALOGW("Skipping route to sink \"%s\" as it likely has vendor extension type",
+ sinkAttr.c_str());
+ return NO_INIT;
}
route->setSink(sink);
std::string sourcesAttr = getXmlAttribute(cur, Attributes::sources);
if (sourcesAttr.empty()) {
ALOGE("%s: No %s found", __func__, Attributes::sources);
- return Status::fromStatusT(BAD_VALUE);
+ return BAD_VALUE;
}
// Tokenize and Convert Sources name to port pointer
PolicyAudioPortVector sources;
@@ -594,11 +614,15 @@
while (devTag != NULL) {
if (strlen(devTag) != 0) {
sp<PolicyAudioPort> source = ctx->findPortByTagName(devTag);
- if (source == NULL) {
+ if (source == NULL && !mIgnoreVendorExtensions) {
ALOGE("%s: no source found with name=%s", __func__, devTag);
- return Status::fromStatusT(BAD_VALUE);
+ return BAD_VALUE;
+ } else if (source == NULL) {
+ ALOGW("Skipping route source \"%s\" as it likely has vendor extension type",
+ devTag);
+ } else {
+ sources.add(source);
}
- sources.add(source);
}
devTag = strtok(NULL, ",");
}
@@ -613,7 +637,7 @@
}
template<>
-Return<ModuleTraits::Element> PolicySerializer::deserialize<ModuleTraits>(
+std::variant<status_t, ModuleTraits::Element> PolicySerializer::deserialize<ModuleTraits>(
const xmlNode *cur, ModuleTraits::PtrSerializingCtx ctx)
{
using Attributes = ModuleTraits::Attributes;
@@ -625,7 +649,7 @@
std::string name = getXmlAttribute(cur, Attributes::name);
if (name.empty()) {
ALOGE("%s: No %s found", __func__, Attributes::name);
- return Status::fromStatusT(BAD_VALUE);
+ return BAD_VALUE;
}
uint32_t versionMajor = 0, versionMinor = 0;
std::string versionLiteral = getXmlAttribute(cur, Attributes::version);
@@ -643,21 +667,21 @@
MixPortTraits::Collection mixPorts;
status_t status = deserializeCollection<MixPortTraits>(cur, &mixPorts, NULL);
if (status != NO_ERROR) {
- return Status::fromStatusT(status);
+ return status;
}
module->setProfiles(mixPorts);
DevicePortTraits::Collection devicePorts;
status = deserializeCollection<DevicePortTraits>(cur, &devicePorts, NULL);
if (status != NO_ERROR) {
- return Status::fromStatusT(status);
+ return status;
}
module->setDeclaredDevices(devicePorts);
RouteTraits::Collection routes;
status = deserializeCollection<RouteTraits>(cur, &routes, module.get());
if (status != NO_ERROR) {
- return Status::fromStatusT(status);
+ return status;
}
module->setRoutes(routes);
@@ -677,6 +701,12 @@
sp<DeviceDescriptor> device = module->getDeclaredDevices().
getDeviceFromTagName(std::string(reinterpret_cast<const char*>(
attachedDevice.get())));
+ if (device == nullptr && mIgnoreVendorExtensions) {
+ ALOGW("Skipped attached device \"%s\" because it likely uses a vendor"
+ "extension type",
+ reinterpret_cast<const char*>(attachedDevice.get()));
+ continue;
+ }
ctx->addDevice(device);
}
}
@@ -703,7 +733,8 @@
}
template<>
-Return<GlobalConfigTraits::Element> PolicySerializer::deserialize<GlobalConfigTraits>(
+std::variant<status_t, GlobalConfigTraits::Element>
+PolicySerializer::deserialize<GlobalConfigTraits>(
const xmlNode *root, GlobalConfigTraits::PtrSerializingCtx config)
{
using Attributes = GlobalConfigTraits::Attributes;
@@ -725,14 +756,15 @@
if (!engineLibrarySuffix.empty()) {
config->setEngineLibraryNameSuffix(engineLibrarySuffix);
}
- return Void();
+ return NO_ERROR;
}
}
- return Void();
+ return NO_ERROR;
}
template<>
-Return<SurroundSoundTraits::Element> PolicySerializer::deserialize<SurroundSoundTraits>(
+std::variant<status_t, SurroundSoundTraits::Element>
+PolicySerializer::deserialize<SurroundSoundTraits>(
const xmlNode *root, SurroundSoundTraits::PtrSerializingCtx config)
{
config->setDefaultSurroundFormats();
@@ -745,14 +777,15 @@
if (status == NO_ERROR) {
config->setSurroundFormats(formats);
}
- return Void();
+ return NO_ERROR;
}
}
- return Void();
+ return NO_ERROR;
}
template<>
-Return<SurroundSoundFormatTraits::Element> PolicySerializer::deserialize<SurroundSoundFormatTraits>(
+std::variant<status_t, SurroundSoundFormatTraits::Element>
+PolicySerializer::deserialize<SurroundSoundFormatTraits>(
const xmlNode *cur, SurroundSoundFormatTraits::PtrSerializingCtx /*serializingContext*/)
{
using Attributes = SurroundSoundFormatTraits::Attributes;
@@ -760,12 +793,16 @@
std::string formatLiteral = getXmlAttribute(cur, Attributes::name);
if (formatLiteral.empty()) {
ALOGE("%s: No %s found for a surround format", __func__, Attributes::name);
- return Status::fromStatusT(BAD_VALUE);
+ return BAD_VALUE;
+ }
+ if (mIgnoreVendorExtensions && maybeVendorExtension(formatLiteral)) {
+ ALOGI("%s: vendor extension format \"%s\" skipped", __func__, formatLiteral.c_str());
+ return NO_INIT;
}
audio_format_t format = formatFromString(formatLiteral);
if (format == AUDIO_FORMAT_DEFAULT) {
ALOGE("%s: Unrecognized format %s", __func__, formatLiteral.c_str());
- return Status::fromStatusT(BAD_VALUE);
+ return BAD_VALUE;
}
SurroundSoundFormatTraits::Element pair = std::make_pair(
format, SurroundSoundFormatTraits::Collection::mapped_type{});
@@ -777,14 +814,16 @@
auto result = pair.second.insert(subformat);
if (!result.second) {
ALOGE("%s: could not add subformat %x to collection", __func__, subformat);
- return Status::fromStatusT(BAD_VALUE);
+ return BAD_VALUE;
}
}
return pair;
}
-status_t PolicySerializer::deserialize(const char *configFile, AudioPolicyConfig *config)
+status_t PolicySerializer::deserialize(const char *configFile, AudioPolicyConfig *config,
+ bool ignoreVendorExtensions)
{
+ mIgnoreVendorExtensions = ignoreVendorExtensions;
auto doc = make_xmlUnique(xmlParseFile(configFile));
if (doc == nullptr) {
ALOGE("%s: Could not parse %s document.", __func__, configFile);
@@ -845,4 +884,12 @@
return status;
}
+status_t deserializeAudioPolicyFileForVts(const char *fileName, AudioPolicyConfig *config)
+{
+ PolicySerializer serializer;
+ status_t status = serializer.deserialize(fileName, config, true /*ignoreVendorExtensions*/);
+ if (status != OK) config->clear();
+ return status;
+}
+
} // namespace android
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index d038ce5..380bf6b 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -142,47 +142,19 @@
return EngineBase::setForceUse(usage, config);
}
-DeviceVector Engine::getDevicesForStrategyInt(legacy_strategy strategy,
- DeviceVector availableOutputDevices,
- DeviceVector availableInputDevices,
- const SwAudioOutputCollection &outputs) const
+void Engine::filterOutputDevicesForStrategy(legacy_strategy strategy,
+ DeviceVector& availableOutputDevices,
+ const DeviceVector availableInputDevices,
+ const SwAudioOutputCollection &outputs) const
{
- DeviceVector devices;
-
switch (strategy) {
-
- case STRATEGY_TRANSMITTED_THROUGH_SPEAKER:
- devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER);
- break;
-
- case STRATEGY_SONIFICATION_RESPECTFUL:
- if (isInCall() || outputs.isActiveLocally(toVolumeSource(AUDIO_STREAM_VOICE_CALL))) {
- devices = getDevicesForStrategyInt(
- STRATEGY_SONIFICATION, availableOutputDevices, availableInputDevices, outputs);
- } else {
- bool media_active_locally =
- outputs.isActiveLocally(toVolumeSource(AUDIO_STREAM_MUSIC),
- SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)
- || outputs.isActiveLocally(
- toVolumeSource(AUDIO_STREAM_ACCESSIBILITY),
- SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY);
+ case STRATEGY_SONIFICATION_RESPECTFUL: {
+ if (!(isInCall() || outputs.isActiveLocally(toVolumeSource(AUDIO_STREAM_VOICE_CALL)))) {
// routing is same as media without the "remote" device
availableOutputDevices.remove(availableOutputDevices.getDevicesFromType(
AUDIO_DEVICE_OUT_REMOTE_SUBMIX));
- devices = getDevicesForStrategyInt(STRATEGY_MEDIA,
- availableOutputDevices,
- availableInputDevices, outputs);
- // if no media is playing on the device, check for mandatory use of "safe" speaker
- // when media would have played on speaker, and the safe speaker path is available
- if (!media_active_locally) {
- devices.replaceDevicesByType(
- AUDIO_DEVICE_OUT_SPEAKER,
- availableOutputDevices.getDevicesFromType(
- AUDIO_DEVICE_OUT_SPEAKER_SAFE));
- }
}
- break;
-
+ } break;
case STRATEGY_DTMF:
case STRATEGY_PHONE: {
// Force use of only devices on primary output if:
@@ -214,6 +186,64 @@
availableOutputDevices = availPrimaryOutputDevices;
}
}
+ } break;
+ case STRATEGY_ACCESSIBILITY: {
+ // do not route accessibility prompts to a digital output currently configured with a
+ // compressed format as they would likely not be mixed and dropped.
+ for (size_t i = 0; i < outputs.size(); i++) {
+ sp<AudioOutputDescriptor> desc = outputs.valueAt(i);
+ if (desc->isActive() && !audio_is_linear_pcm(desc->getFormat())) {
+ availableOutputDevices.remove(desc->devices().getDevicesFromTypes({
+ AUDIO_DEVICE_OUT_HDMI, AUDIO_DEVICE_OUT_SPDIF,
+ AUDIO_DEVICE_OUT_HDMI_ARC}));
+ }
+ }
+ } break;
+ default:
+ break;
+ }
+}
+
+DeviceVector Engine::getDevicesForStrategyInt(legacy_strategy strategy,
+ DeviceVector availableOutputDevices,
+ DeviceVector availableInputDevices,
+ const SwAudioOutputCollection &outputs) const
+{
+ DeviceVector devices;
+
+ switch (strategy) {
+
+ case STRATEGY_TRANSMITTED_THROUGH_SPEAKER:
+ devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER);
+ break;
+
+ case STRATEGY_SONIFICATION_RESPECTFUL:
+ if (isInCall() || outputs.isActiveLocally(toVolumeSource(AUDIO_STREAM_VOICE_CALL))) {
+ devices = getDevicesForStrategyInt(
+ STRATEGY_SONIFICATION, availableOutputDevices, availableInputDevices, outputs);
+ } else {
+ bool media_active_locally =
+ outputs.isActiveLocally(toVolumeSource(AUDIO_STREAM_MUSIC),
+ SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)
+ || outputs.isActiveLocally(
+ toVolumeSource(AUDIO_STREAM_ACCESSIBILITY),
+ SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY);
+ devices = getDevicesForStrategyInt(STRATEGY_MEDIA,
+ availableOutputDevices,
+ availableInputDevices, outputs);
+ // if no media is playing on the device, check for mandatory use of "safe" speaker
+ // when media would have played on speaker, and the safe speaker path is available
+ if (!media_active_locally) {
+ devices.replaceDevicesByType(
+ AUDIO_DEVICE_OUT_SPEAKER,
+ availableOutputDevices.getDevicesFromType(
+ AUDIO_DEVICE_OUT_SPEAKER_SAFE));
+ }
+ }
+ break;
+
+ case STRATEGY_DTMF:
+ case STRATEGY_PHONE: {
devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_HEARING_AID);
if (!devices.isEmpty()) break;
devices = availableOutputDevices.getFirstDevicesFromTypes({
@@ -286,16 +316,6 @@
case STRATEGY_ACCESSIBILITY:
if (strategy == STRATEGY_ACCESSIBILITY) {
- // do not route accessibility prompts to a digital output currently configured with a
- // compressed format as they would likely not be mixed and dropped.
- for (size_t i = 0; i < outputs.size(); i++) {
- sp<AudioOutputDescriptor> desc = outputs.valueAt(i);
- if (desc->isActive() && !audio_is_linear_pcm(desc->getFormat())) {
- availableOutputDevices.remove(desc->devices().getDevicesFromTypes({
- AUDIO_DEVICE_OUT_HDMI, AUDIO_DEVICE_OUT_SPDIF,
- AUDIO_DEVICE_OUT_HDMI_ARC}));
- }
- }
if (outputs.isActive(toVolumeSource(AUDIO_STREAM_RING)) ||
outputs.isActive(toVolumeSource(AUDIO_STREAM_ALARM))) {
return getDevicesForStrategyInt(
@@ -634,11 +654,18 @@
auto legacyStrategy = mLegacyStrategyMap.find(strategy) != end(mLegacyStrategyMap) ?
mLegacyStrategyMap.at(strategy) : STRATEGY_NONE;
- // When not in call, STRATEGY_PHONE and STRATEGY_DTMF follow STRATEGY_MEDIA
- if (!isInCall() && (legacyStrategy == STRATEGY_PHONE || legacyStrategy == STRATEGY_DTMF)) {
+ // When not in call, STRATEGY_DTMF follows STRATEGY_MEDIA
+ if (!isInCall() && legacyStrategy == STRATEGY_DTMF) {
legacyStrategy = STRATEGY_MEDIA;
strategy = getProductStrategyFromLegacy(STRATEGY_MEDIA);
}
+
+ DeviceVector availableInputDevices = getApmObserver()->getAvailableInputDevices();
+ const SwAudioOutputCollection& outputs = getApmObserver()->getOutputs();
+
+ filterOutputDevicesForStrategy(legacyStrategy, availableOutputDevices,
+ availableInputDevices, outputs);
+
// check if this strategy has a preferred device that is available,
// if yes, give priority to it.
DeviceVector preferredAvailableDevVec =
@@ -647,9 +674,6 @@
return preferredAvailableDevVec;
}
- DeviceVector availableInputDevices = getApmObserver()->getAvailableInputDevices();
- const SwAudioOutputCollection& outputs = getApmObserver()->getOutputs();
-
return getDevicesForStrategyInt(legacyStrategy,
availableOutputDevices,
availableInputDevices, outputs);
diff --git a/services/audiopolicy/enginedefault/src/Engine.h b/services/audiopolicy/enginedefault/src/Engine.h
index 6214fe7..6dc6cd0 100644
--- a/services/audiopolicy/enginedefault/src/Engine.h
+++ b/services/audiopolicy/enginedefault/src/Engine.h
@@ -74,6 +74,11 @@
status_t setDefaultDevice(audio_devices_t device);
+ void filterOutputDevicesForStrategy(legacy_strategy strategy,
+ DeviceVector& availableOutputDevices,
+ const DeviceVector availableInputDevices,
+ const SwAudioOutputCollection &outputs) const;
+
DeviceVector getDevicesForStrategyInt(legacy_strategy strategy,
DeviceVector availableOutputDevices,
DeviceVector availableInputDevices,
diff --git a/services/audiopolicy/fuzzer/Android.bp b/services/audiopolicy/fuzzer/Android.bp
index 5dbcebd..38bdedc 100644
--- a/services/audiopolicy/fuzzer/Android.bp
+++ b/services/audiopolicy/fuzzer/Android.bp
@@ -50,6 +50,7 @@
"libbinder",
"libaudiopolicy",
"libaudiopolicymanagerdefault",
+ "media_permission-aidl-cpp",
],
static_libs: [
"android.hardware.audio.common@7.0-enums",
diff --git a/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp b/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
index 692ce08..1177b95 100644
--- a/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
+++ b/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
@@ -26,6 +26,7 @@
#include <Serializer.h>
#include <android-base/file.h>
+#include <android/media/permission/Identity.h>
#include <libxml/parser.h>
#include <libxml/xinclude.h>
#include <media/AudioPolicy.h>
@@ -46,6 +47,8 @@
using namespace ::android::audio::policy::configuration::V7_0;
}
+using media::permission::Identity;
+
static const std::vector<audio_format_t> kAudioFormats = [] {
std::vector<audio_format_t> result;
for (const auto enumVal : xsdc_enum_range<xsd::AudioFormat>{}) {
@@ -246,7 +249,10 @@
*portId = AUDIO_PORT_HANDLE_NONE;
AudioPolicyInterface::output_type_t outputType;
- if (mManager->getOutputForAttr(&attr, output, AUDIO_SESSION_NONE, &stream, 0 /*uid*/, &config,
+ // TODO b/182392769: use identity util
+ Identity i;
+ i.uid = 0;
+ if (mManager->getOutputForAttr(&attr, output, AUDIO_SESSION_NONE, &stream, i, &config,
&flags, selectedDeviceId, portId, {}, &outputType) != OK) {
return false;
}
@@ -270,7 +276,9 @@
*portId = AUDIO_PORT_HANDLE_NONE;
AudioPolicyInterface::input_type_t inputType;
- if (mManager->getInputForAttr(&attr, &input, riid, AUDIO_SESSION_NONE, 0 /*uid*/, &config,
+ Identity i;
+ i.uid = 0;
+ if (mManager->getInputForAttr(&attr, &input, riid, AUDIO_SESSION_NONE, i, &config,
flags, selectedDeviceId, &inputType, portId) != OK) {
return false;
}
diff --git a/services/audiopolicy/managerdefault/Android.bp b/services/audiopolicy/managerdefault/Android.bp
index 5572beb..b111db4 100644
--- a/services/audiopolicy/managerdefault/Android.bp
+++ b/services/audiopolicy/managerdefault/Android.bp
@@ -34,6 +34,8 @@
// a dependency on it in the device makefile. There will be no build time
// conflict with libaudiopolicyenginedefault.
"libaudiopolicyenginedefault",
+ "media_permission-aidl-cpp",
+ "libaudioclient_aidl_conversion",
],
header_libs: [
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 75f0c1b..2b9f8d7 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -52,6 +52,8 @@
namespace android {
+using media::permission::Identity;
+
//FIXME: workaround for truncated touch sounds
// to be removed when the problem is handled by system UI
#define TOUCH_SOUND_FIXED_DELAY_MS 100
@@ -261,11 +263,7 @@
} else {
checkCloseOutputs();
}
-
- if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL && hasPrimaryOutput()) {
- DeviceVector newDevices = getNewOutputDevices(mPrimaryOutput, false /*fromCache*/);
- updateCallRouting(newDevices);
- }
+ (void)updateCallRouting(false /*fromCache*/);
std::vector<audio_io_handle_t> outputsToReopen;
const DeviceVector msdOutDevices = getMsdAudioOutDevices();
const DeviceVector activeMediaDevices =
@@ -382,10 +380,7 @@
// getDeviceForStrategy() cache
updateDevicesAndOutputs();
- if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL && hasPrimaryOutput()) {
- DeviceVector newDevices = getNewOutputDevices(mPrimaryOutput, false /*fromCache*/);
- updateCallRouting(newDevices);
- }
+ (void)updateCallRouting(false /*fromCache*/);
// Reconnect Audio Source
for (const auto &strategy : mEngine->getOrderedProductStrategies()) {
auto attributes = mEngine->getAllAttributesForProductStrategy(strategy).front();
@@ -550,23 +545,58 @@
return status;
}
-uint32_t AudioPolicyManager::updateCallRouting(const DeviceVector &rxDevices, uint32_t delayMs)
+DeviceVector AudioPolicyManager::selectBestRxSinkDevicesForCall(bool fromCache)
+{
+ DeviceVector rxSinkdevices{};
+ rxSinkdevices = mEngine->getOutputDevicesForAttributes(
+ attributes_initializer(AUDIO_USAGE_VOICE_COMMUNICATION), nullptr, fromCache);
+ if (!rxSinkdevices.isEmpty() && mAvailableOutputDevices.contains(rxSinkdevices.itemAt(0))) {
+ auto rxSinkDevice = rxSinkdevices.itemAt(0);
+ auto telephonyRxModule = mHwModules.getModuleForDeviceType(
+ AUDIO_DEVICE_IN_TELEPHONY_RX, AUDIO_FORMAT_DEFAULT);
+ // retrieve Rx Source device descriptor
+ sp<DeviceDescriptor> rxSourceDevice = mAvailableInputDevices.getDevice(
+ AUDIO_DEVICE_IN_TELEPHONY_RX, String8(), AUDIO_FORMAT_DEFAULT);
+
+ // RX Telephony and Rx sink devices are declared by Primary Audio HAL
+ if (isPrimaryModule(telephonyRxModule) && (telephonyRxModule->getHalVersionMajor() >= 3) &&
+ telephonyRxModule->supportsPatch(rxSourceDevice, rxSinkDevice)) {
+ ALOGW("%s() device %s using HW Bridge", __func__, rxSinkDevice->toString().c_str());
+ return DeviceVector(rxSinkDevice);
+ }
+ }
+ // Note that despite the fact that getNewOutputDevices() is called on the primary output,
+ // the device returned is not necessarily reachable via this output
+ // (filter later by setOutputDevices())
+ return getNewOutputDevices(mPrimaryOutput, fromCache);
+}
+
+status_t AudioPolicyManager::updateCallRouting(bool fromCache, uint32_t delayMs, uint32_t *waitMs)
+{
+ if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL && hasPrimaryOutput()) {
+ DeviceVector rxDevices = selectBestRxSinkDevicesForCall(fromCache);
+ return updateCallRoutingInternal(rxDevices, delayMs, waitMs);
+ }
+ return INVALID_OPERATION;
+}
+
+status_t AudioPolicyManager::updateCallRoutingInternal(
+ const DeviceVector &rxDevices, uint32_t delayMs, uint32_t *waitMs)
{
bool createTxPatch = false;
bool createRxPatch = false;
uint32_t muteWaitMs = 0;
-
if(!hasPrimaryOutput() ||
mPrimaryOutput->devices().onlyContainsDevicesWithType(AUDIO_DEVICE_OUT_STUB)) {
- return muteWaitMs;
+ return INVALID_OPERATION;
}
- ALOG_ASSERT(!rxDevices.isEmpty(), "updateCallRouting() no selected output device");
+ ALOG_ASSERT(!rxDevices.isEmpty(), "%s() no selected output device", __func__);
audio_attributes_t attr = { .source = AUDIO_SOURCE_VOICE_COMMUNICATION };
auto txSourceDevice = mEngine->getInputDeviceForAttributes(attr);
- ALOG_ASSERT(txSourceDevice != 0, "updateCallRouting() input selected device not available");
+ ALOG_ASSERT(txSourceDevice != 0, "%s() input selected device not available", __func__);
- ALOGV("updateCallRouting device rxDevice %s txDevice %s",
+ ALOGV("%s device rxDevice %s txDevice %s", __func__,
rxDevices.itemAt(0)->toString().c_str(), txSourceDevice->toString().c_str());
disconnectTelephonyRxAudioSource();
@@ -595,8 +625,8 @@
(telephonyRxModule->getHalVersionMajor() >= 3)) {
if (rxSourceDevice == 0 || txSinkDevice == 0) {
// RX / TX Telephony device(s) is(are) not currently available
- ALOGE("updateCallRouting() no telephony Tx and/or RX device");
- return muteWaitMs;
+ ALOGE("%s() no telephony Tx and/or RX device", __func__);
+ return INVALID_OPERATION;
}
// createAudioPatchInternal now supports both HW / SW bridging
createRxPatch = true;
@@ -634,8 +664,10 @@
}
mCallTxPatch = createTelephonyPatch(false /*isRx*/, txSourceDevice, delayMs);
}
-
- return muteWaitMs;
+ if (waitMs != nullptr) {
+ *waitMs = muteWaitMs;
+ }
+ return NO_ERROR;
}
sp<AudioPatch> AudioPolicyManager::createTelephonyPatch(
@@ -753,25 +785,22 @@
}
if (hasPrimaryOutput()) {
- // Note that despite the fact that getNewOutputDevices() is called on the primary output,
- // the device returned is not necessarily reachable via this output
- DeviceVector rxDevices = getNewOutputDevices(mPrimaryOutput, false /*fromCache*/);
- // force routing command to audio hardware when ending call
- // even if no device change is needed
- if (isStateInCall(oldState) && rxDevices.isEmpty()) {
- rxDevices = mPrimaryOutput->devices();
- }
-
if (state == AUDIO_MODE_IN_CALL) {
- updateCallRouting(rxDevices, delayMs);
- } else if (oldState == AUDIO_MODE_IN_CALL) {
- disconnectTelephonyRxAudioSource();
- if (mCallTxPatch != 0) {
- releaseAudioPatchInternal(mCallTxPatch->getHandle());
- mCallTxPatch.clear();
- }
- setOutputDevices(mPrimaryOutput, rxDevices, force, 0);
+ (void)updateCallRouting(false /*fromCache*/, delayMs);
} else {
+ DeviceVector rxDevices = getNewOutputDevices(mPrimaryOutput, false /*fromCache*/);
+ // force routing command to audio hardware when ending call
+ // even if no device change is needed
+ if (isStateInCall(oldState) && rxDevices.isEmpty()) {
+ rxDevices = mPrimaryOutput->devices();
+ }
+ if (oldState == AUDIO_MODE_IN_CALL) {
+ disconnectTelephonyRxAudioSource();
+ if (mCallTxPatch != 0) {
+ releaseAudioPatchInternal(mCallTxPatch->getHandle());
+ mCallTxPatch.clear();
+ }
+ }
setOutputDevices(mPrimaryOutput, rxDevices, force, 0);
}
}
@@ -1103,7 +1132,7 @@
audio_io_handle_t *output,
audio_session_t session,
audio_stream_type_t *stream,
- uid_t uid,
+ const Identity& identity,
const audio_config_t *config,
audio_output_flags_t *flags,
audio_port_handle_t *selectedDeviceId,
@@ -1115,6 +1144,8 @@
if (*portId != AUDIO_PORT_HANDLE_NONE) {
return INVALID_OPERATION;
}
+ const uid_t uid = VALUE_OR_RETURN_STATUS(
+ aidl2legacy_int32_t_uid_t(identity.uid));
const audio_port_handle_t requestedPortId = *selectedDeviceId;
audio_attributes_t resultAttr;
bool isRequestedDeviceForExclusiveUse = false;
@@ -2083,7 +2114,7 @@
audio_io_handle_t *input,
audio_unique_id_t riid,
audio_session_t session,
- uid_t uid,
+ const Identity& identity,
const audio_config_base_t *config,
audio_input_flags_t flags,
audio_port_handle_t *selectedDeviceId,
@@ -2102,6 +2133,7 @@
sp<AudioInputDescriptor> inputDesc;
sp<RecordClientDescriptor> clientDesc;
audio_port_handle_t requestedDeviceId = *selectedDeviceId;
+ uid_t uid = VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_uid_t(identity.uid));
bool isSoundTrigger;
// The supplied portId must be AUDIO_PORT_HANDLE_NONE
@@ -3300,9 +3332,7 @@
void AudioPolicyManager::updateCallAndOutputRouting(bool forceVolumeReeval, uint32_t delayMs)
{
uint32_t waitMs = 0;
- if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL && hasPrimaryOutput()) {
- DeviceVector newDevices = getNewOutputDevices(mPrimaryOutput, true /*fromCache*/);
- waitMs = updateCallRouting(newDevices, delayMs);
+ if (updateCallRouting(true /*fromCache*/, delayMs, &waitMs) == NO_ERROR) {
// Only apply special touch sound delay once
delayMs = 0;
}
@@ -4499,68 +4529,28 @@
status_t AudioPolicyManager::getSurroundFormats(unsigned int *numSurroundFormats,
audio_format_t *surroundFormats,
- bool *surroundFormatsEnabled,
- bool reported)
+ bool *surroundFormatsEnabled)
{
- if (numSurroundFormats == NULL || (*numSurroundFormats != 0 &&
- (surroundFormats == NULL || surroundFormatsEnabled == NULL))) {
+ if (numSurroundFormats == nullptr || (*numSurroundFormats != 0 &&
+ (surroundFormats == nullptr || surroundFormatsEnabled == nullptr))) {
return BAD_VALUE;
}
- ALOGV("%s() numSurroundFormats %d surroundFormats %p surroundFormatsEnabled %p reported %d",
- __func__, *numSurroundFormats, surroundFormats, surroundFormatsEnabled, reported);
+ ALOGV("%s() numSurroundFormats %d surroundFormats %p surroundFormatsEnabled %p",
+ __func__, *numSurroundFormats, surroundFormats, surroundFormatsEnabled);
size_t formatsWritten = 0;
size_t formatsMax = *numSurroundFormats;
- std::unordered_set<audio_format_t> formats; // Uses primary surround formats only
- if (reported) {
- // Return formats from all device profiles that have already been resolved by
- // checkOutputsForDevice().
- for (size_t i = 0; i < mAvailableOutputDevices.size(); i++) {
- sp<DeviceDescriptor> device = mAvailableOutputDevices[i];
- audio_devices_t deviceType = device->type();
- // Enabling/disabling formats are applied to only HDMI devices. So, this function
- // returns formats reported by HDMI devices.
- if (deviceType != AUDIO_DEVICE_OUT_HDMI) {
- continue;
- }
- // Formats reported by sink devices
- std::unordered_set<audio_format_t> formatset;
- if (auto it = mReportedFormatsMap.find(device); it != mReportedFormatsMap.end()) {
- formatset.insert(it->second.begin(), it->second.end());
- }
- // Formats hard-coded in the in policy configuration file (if any).
- FormatVector encodedFormats = device->encodedFormats();
- formatset.insert(encodedFormats.begin(), encodedFormats.end());
- // Filter the formats which are supported by the vendor hardware.
- for (auto it = formatset.begin(); it != formatset.end(); ++it) {
- if (mConfig.getSurroundFormats().count(*it) != 0) {
- formats.insert(*it);
- } else {
- for (const auto& pair : mConfig.getSurroundFormats()) {
- if (pair.second.count(*it) != 0) {
- formats.insert(pair.first);
- break;
- }
- }
- }
- }
- }
- } else {
- for (const auto& pair : mConfig.getSurroundFormats()) {
- formats.insert(pair.first);
- }
- }
- *numSurroundFormats = formats.size();
+ *numSurroundFormats = mConfig.getSurroundFormats().size();
audio_policy_forced_cfg_t forceUse = mEngine->getForceUse(
AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND);
- for (const auto& format: formats) {
+ for (const auto& format: mConfig.getSurroundFormats()) {
if (formatsWritten < formatsMax) {
- surroundFormats[formatsWritten] = format;
+ surroundFormats[formatsWritten] = format.first;
bool formatEnabled = true;
switch (forceUse) {
case AUDIO_POLICY_FORCE_ENCODED_SURROUND_MANUAL:
- formatEnabled = mManualSurroundFormats.count(format) != 0;
+ formatEnabled = mManualSurroundFormats.count(format.first) != 0;
break;
case AUDIO_POLICY_FORCE_ENCODED_SURROUND_NEVER:
formatEnabled = false;
@@ -4574,6 +4564,60 @@
return NO_ERROR;
}
+status_t AudioPolicyManager::getReportedSurroundFormats(unsigned int *numSurroundFormats,
+ audio_format_t *surroundFormats) {
+ if (numSurroundFormats == nullptr || (*numSurroundFormats != 0 && surroundFormats == nullptr)) {
+ return BAD_VALUE;
+ }
+ ALOGV("%s() numSurroundFormats %d surroundFormats %p",
+ __func__, *numSurroundFormats, surroundFormats);
+
+ size_t formatsWritten = 0;
+ size_t formatsMax = *numSurroundFormats;
+ std::unordered_set<audio_format_t> formats; // Uses primary surround formats only
+
+ // Return formats from all device profiles that have already been resolved by
+ // checkOutputsForDevice().
+ for (size_t i = 0; i < mAvailableOutputDevices.size(); i++) {
+ sp<DeviceDescriptor> device = mAvailableOutputDevices[i];
+ audio_devices_t deviceType = device->type();
+ // Enabling/disabling formats are applied to only HDMI devices. So, this function
+ // returns formats reported by HDMI devices.
+ if (deviceType != AUDIO_DEVICE_OUT_HDMI) {
+ continue;
+ }
+ // Formats reported by sink devices
+ std::unordered_set<audio_format_t> formatset;
+ if (auto it = mReportedFormatsMap.find(device); it != mReportedFormatsMap.end()) {
+ formatset.insert(it->second.begin(), it->second.end());
+ }
+
+ // Formats hard-coded in the in policy configuration file (if any).
+ FormatVector encodedFormats = device->encodedFormats();
+ formatset.insert(encodedFormats.begin(), encodedFormats.end());
+ // Filter the formats which are supported by the vendor hardware.
+ for (auto it = formatset.begin(); it != formatset.end(); ++it) {
+ if (mConfig.getSurroundFormats().count(*it) != 0) {
+ formats.insert(*it);
+ } else {
+ for (const auto& pair : mConfig.getSurroundFormats()) {
+ if (pair.second.count(*it) != 0) {
+ formats.insert(pair.first);
+ break;
+ }
+ }
+ }
+ }
+ }
+ *numSurroundFormats = formats.size();
+ for (const auto& format: formats) {
+ if (formatsWritten < formatsMax) {
+ surroundFormats[formatsWritten++] = format;
+ }
+ }
+ return NO_ERROR;
+}
+
status_t AudioPolicyManager::setSurroundFormatEnabled(audio_format_t audioFormat, bool enabled)
{
ALOGV("%s() format 0x%X enabled %d", __func__, audioFormat, enabled);
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index bf73f75..f5dd20c 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -116,7 +116,7 @@
audio_io_handle_t *output,
audio_session_t session,
audio_stream_type_t *stream,
- uid_t uid,
+ const media::permission::Identity& identity,
const audio_config_t *config,
audio_output_flags_t *flags,
audio_port_handle_t *selectedDeviceId,
@@ -130,7 +130,7 @@
audio_io_handle_t *input,
audio_unique_id_t riid,
audio_session_t session,
- uid_t uid,
+ const media::permission::Identity& identity,
const audio_config_base_t *config,
audio_input_flags_t flags,
audio_port_handle_t *selectedDeviceId,
@@ -313,8 +313,9 @@
virtual status_t getSurroundFormats(unsigned int *numSurroundFormats,
audio_format_t *surroundFormats,
- bool *surroundFormatsEnabled,
- bool reported);
+ bool *surroundFormatsEnabled);
+ virtual status_t getReportedSurroundFormats(unsigned int *numSurroundFormats,
+ audio_format_t *surroundFormats);
virtual status_t setSurroundFormatEnabled(audio_format_t audioFormat, bool enabled);
virtual status_t getHwOffloadEncodingFormatsSupportedForA2DP(
@@ -735,9 +736,22 @@
String8(devices.itemAt(0)->address().c_str()) : String8("");
}
- uint32_t updateCallRouting(const DeviceVector &rxDevices, uint32_t delayMs = 0);
+ status_t updateCallRouting(
+ bool fromCache, uint32_t delayMs = 0, uint32_t *waitMs = nullptr);
+ status_t updateCallRoutingInternal(
+ const DeviceVector &rxDevices, uint32_t delayMs, uint32_t *waitMs);
sp<AudioPatch> createTelephonyPatch(bool isRx, const sp<DeviceDescriptor> &device,
uint32_t delayMs);
+ /**
+ * @brief selectBestRxSinkDevicesForCall: if the primary module host both Telephony Rx/Tx
+ * devices, and it declares also supporting a HW bridge between the Telephony Rx and the
+ * given sink device for Voice Call audio attributes, select this device in prio.
+ * Otherwise, getNewOutputDevices() is called on the primary output to select sink device.
+ * @param fromCache true to prevent engine reconsidering all product strategies and retrieve
+ * from engine cache.
+ * @return vector of devices, empty if none is found.
+ */
+ DeviceVector selectBestRxSinkDevicesForCall(bool fromCache);
bool isDeviceOfModule(const sp<DeviceDescriptor>& devDesc, const char *moduleId) const;
status_t startSource(const sp<SwAudioOutputDescriptor>& outputDesc,
diff --git a/services/audiopolicy/service/Android.bp b/services/audiopolicy/service/Android.bp
index 439f9f0..d5ba756 100644
--- a/services/audiopolicy/service/Android.bp
+++ b/services/audiopolicy/service/Android.bp
@@ -44,10 +44,12 @@
"audiopolicy-aidl-cpp",
"audiopolicy-types-aidl-cpp",
"capture_state_listener-aidl-cpp",
+ "media_permission-aidl-cpp",
],
static_libs: [
"libaudiopolicycomponents",
+ "media_permission-aidl-cpp",
],
header_libs: [
@@ -66,5 +68,6 @@
export_shared_lib_headers: [
"libsensorprivacy",
+ "media_permission-aidl-cpp",
],
}
diff --git a/services/audiopolicy/service/AudioPolicyEffects.cpp b/services/audiopolicy/service/AudioPolicyEffects.cpp
index b738633..8426a77 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.cpp
+++ b/services/audiopolicy/service/AudioPolicyEffects.cpp
@@ -35,6 +35,8 @@
namespace android {
+using media::permission::Identity;
+
// ----------------------------------------------------------------------------
// AudioPolicyEffects Implementation
// ----------------------------------------------------------------------------
@@ -121,7 +123,9 @@
Vector <EffectDesc *> effects = mInputSources.valueAt(index)->mEffects;
for (size_t i = 0; i < effects.size(); i++) {
EffectDesc *effect = effects[i];
- sp<AudioEffect> fx = new AudioEffect(String16("android"));
+ Identity identity;
+ identity.packageName = "android";
+ sp<AudioEffect> fx = new AudioEffect(identity);
fx->set(NULL, &effect->mUuid, -1, 0, 0, audioSession, input);
status_t status = fx->initCheck();
if (status != NO_ERROR && status != ALREADY_EXISTS) {
@@ -270,7 +274,9 @@
Vector <EffectDesc *> effects = mOutputStreams.valueAt(index)->mEffects;
for (size_t i = 0; i < effects.size(); i++) {
EffectDesc *effect = effects[i];
- sp<AudioEffect> fx = new AudioEffect(String16("android"));
+ Identity identity;
+ identity.packageName = "android";
+ sp<AudioEffect> fx = new AudioEffect(identity);
fx->set(NULL, &effect->mUuid, 0, 0, 0, audioSession, output);
status_t status = fx->initCheck();
if (status != NO_ERROR && status != ALREADY_EXISTS) {
@@ -970,7 +976,9 @@
for (const auto& deviceEffectsIter : mDeviceEffects) {
const auto& deviceEffects = deviceEffectsIter.second;
for (const auto& effectDesc : deviceEffects->mEffectDescriptors->mEffects) {
- auto fx = std::make_unique<AudioEffect>(String16("android"));
+ Identity identity;
+ identity.packageName = "android";
+ sp<AudioEffect> fx = new AudioEffect(identity);
fx->set(EFFECT_UUID_NULL, &effectDesc->mUuid, 0, nullptr,
nullptr, AUDIO_SESSION_DEVICE, AUDIO_IO_HANDLE_NONE,
AudioDeviceTypeAddr{deviceEffects->getDeviceType(),
@@ -987,7 +995,7 @@
ALOGV("%s(): create Fx %s added on port type=%d address=%s", __func__,
effectDesc->mName, deviceEffects->getDeviceType(),
deviceEffects->getDeviceAddress().c_str());
- deviceEffects->mEffects.push_back(std::move(fx));
+ deviceEffects->mEffects.push_back(fx);
}
}
}
diff --git a/services/audiopolicy/service/AudioPolicyEffects.h b/services/audiopolicy/service/AudioPolicyEffects.h
index 81c728d..13d5d0c 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.h
+++ b/services/audiopolicy/service/AudioPolicyEffects.h
@@ -207,7 +207,7 @@
mDeviceType(device), mDeviceAddress(address) {}
/*virtual*/ ~DeviceEffects() = default;
- std::vector<std::unique_ptr<AudioEffect>> mEffects;
+ std::vector< sp<AudioEffect> > mEffects;
audio_devices_t getDeviceType() const { return mDeviceType; }
std::string getDeviceAddress() const { return mDeviceAddress; }
const std::unique_ptr<EffectDescVector> mEffectDescriptors;
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 07122cc..639fa58 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -25,6 +25,7 @@
#include <media/MediaMetricsItem.h>
#include <media/PolicyAidlConversion.h>
#include <utils/Log.h>
+#include <android/media/permission/Identity.h>
#define VALUE_OR_RETURN_BINDER_STATUS(x) \
({ auto _tmp = (x); \
@@ -42,6 +43,7 @@
namespace android {
using binder::Status;
using aidl_utils::binderStatusFromStatusT;
+using media::permission::Identity;
const std::vector<audio_usage_t>& SYSTEM_USAGES = {
AUDIO_USAGE_CALL_ASSISTANT,
@@ -62,15 +64,15 @@
}
status_t AudioPolicyService::validateUsage(audio_usage_t usage) {
- return validateUsage(usage, IPCThreadState::self()->getCallingPid(),
- IPCThreadState::self()->getCallingUid());
+ return validateUsage(usage, getCallingIdentity());
}
-status_t AudioPolicyService::validateUsage(audio_usage_t usage, pid_t pid, uid_t uid) {
+status_t AudioPolicyService::validateUsage(audio_usage_t usage, const Identity& identity) {
if (isSystemUsage(usage)) {
if (isSupportedSystemUsage(usage)) {
- if (!modifyAudioRoutingAllowed(pid, uid)) {
- ALOGE("permission denied: modify audio routing not allowed for uid %d", uid);
+ if (!modifyAudioRoutingAllowed(identity)) {
+ ALOGE(("permission denied: modify audio routing not allowed "
+ "for identity %s"), identity.toString().c_str());
return PERMISSION_DENIED;
}
} else {
@@ -276,8 +278,7 @@
Status AudioPolicyService::getOutputForAttr(const media::AudioAttributesInternal& attrAidl,
int32_t sessionAidl,
- int32_t pidAidl,
- int32_t uidAidl,
+ const Identity& identity,
const media::AudioConfig& configAidl,
int32_t flagsAidl,
int32_t selectedDeviceIdAidl,
@@ -288,8 +289,6 @@
audio_session_t session = VALUE_OR_RETURN_BINDER_STATUS(
aidl2legacy_int32_t_audio_session_t(sessionAidl));
audio_stream_type_t stream = AUDIO_STREAM_DEFAULT;
- pid_t pid = VALUE_OR_RETURN_BINDER_STATUS(aidl2legacy_int32_t_pid_t(pidAidl));
- uid_t uid = VALUE_OR_RETURN_BINDER_STATUS(aidl2legacy_int32_t_uid_t(uidAidl));
audio_config_t config = VALUE_OR_RETURN_BINDER_STATUS(
aidl2legacy_AudioConfig_audio_config_t(configAidl));
audio_output_flags_t flags = VALUE_OR_RETURN_BINDER_STATUS(
@@ -307,22 +306,28 @@
RETURN_IF_BINDER_ERROR(
binderStatusFromStatusT(AudioValidator::validateAudioAttributes(attr, "68953950")));
- RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(validateUsage(attr.usage, pid, uid)));
+ RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(validateUsage(attr.usage, identity)));
ALOGV("%s()", __func__);
Mutex::Autolock _l(mLock);
+ // TODO b/182392553: refactor or remove
+ Identity adjIdentity = identity;
const uid_t callingUid = IPCThreadState::self()->getCallingUid();
- if (!isAudioServerOrMediaServerUid(callingUid) || uid == (uid_t)-1) {
- ALOGW_IF(uid != (uid_t)-1 && uid != callingUid,
- "%s uid %d tried to pass itself off as %d", __func__, callingUid, uid);
- uid = callingUid;
+ if (!isAudioServerOrMediaServerUid(callingUid) || identity.uid == -1) {
+ int32_t callingUidAidl = VALUE_OR_RETURN_BINDER_STATUS(
+ legacy2aidl_uid_t_int32_t(callingUid));
+ ALOGW_IF(identity.uid != -1 && identity.uid != callingUidAidl,
+ "%s uid %d tried to pass itself off as %d", __func__,
+ callingUidAidl, identity.uid);
+ adjIdentity.uid = callingUidAidl;
}
- if (!mPackageManager.allowPlaybackCapture(uid)) {
+ if (!mPackageManager.allowPlaybackCapture(VALUE_OR_RETURN_BINDER_STATUS(
+ aidl2legacy_int32_t_uid_t(adjIdentity.uid)))) {
attr.flags = static_cast<audio_flags_mask_t>(attr.flags | AUDIO_FLAG_NO_MEDIA_PROJECTION);
}
if (((attr.flags & (AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY|AUDIO_FLAG_BYPASS_MUTE)) != 0)
- && !bypassInterruptionPolicyAllowed(pid, uid)) {
+ && !bypassInterruptionPolicyAllowed(identity)) {
attr.flags = static_cast<audio_flags_mask_t>(
attr.flags & ~(AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY|AUDIO_FLAG_BYPASS_MUTE));
}
@@ -330,7 +335,7 @@
AudioPolicyInterface::output_type_t outputType;
status_t result = mAudioPolicyManager->getOutputForAttr(&attr, &output, session,
&stream,
- uid,
+ adjIdentity,
&config,
&flags, &selectedDeviceId, &portId,
&secondaryOutputs,
@@ -343,16 +348,16 @@
case AudioPolicyInterface::API_OUTPUT_LEGACY:
break;
case AudioPolicyInterface::API_OUTPUT_TELEPHONY_TX:
- if (!modifyPhoneStateAllowed(pid, uid)) {
+ if (!modifyPhoneStateAllowed(adjIdentity)) {
ALOGE("%s() permission denied: modify phone state not allowed for uid %d",
- __func__, uid);
+ __func__, adjIdentity.uid);
result = PERMISSION_DENIED;
}
break;
case AudioPolicyInterface::API_OUT_MIX_PLAYBACK:
- if (!modifyAudioRoutingAllowed(pid, uid)) {
+ if (!modifyAudioRoutingAllowed(adjIdentity)) {
ALOGE("%s() permission denied: modify audio routing not allowed for uid %d",
- __func__, uid);
+ __func__, adjIdentity.uid);
result = PERMISSION_DENIED;
}
break;
@@ -365,8 +370,8 @@
if (result == NO_ERROR) {
sp<AudioPlaybackClient> client =
- new AudioPlaybackClient(attr, output, uid, pid, session, portId, selectedDeviceId,
- stream);
+ new AudioPlaybackClient(attr, output, adjIdentity, session,
+ portId, selectedDeviceId, stream);
mAudioPlaybackClients.add(portId, client);
_aidl_return->output = VALUE_OR_RETURN_BINDER_STATUS(
@@ -502,9 +507,7 @@
int32_t inputAidl,
int32_t riidAidl,
int32_t sessionAidl,
- int32_t pidAidl,
- int32_t uidAidl,
- const std::string& opPackageNameAidl,
+ const Identity& identity,
const media::AudioConfigBase& configAidl,
int32_t flagsAidl,
int32_t selectedDeviceIdAidl,
@@ -517,10 +520,6 @@
aidl2legacy_int32_t_audio_unique_id_t(riidAidl));
audio_session_t session = VALUE_OR_RETURN_BINDER_STATUS(
aidl2legacy_int32_t_audio_session_t(sessionAidl));
- pid_t pid = VALUE_OR_RETURN_BINDER_STATUS(aidl2legacy_int32_t_pid_t(pidAidl));
- uid_t uid = VALUE_OR_RETURN_BINDER_STATUS(aidl2legacy_int32_t_uid_t(uidAidl));
- String16 opPackageName = VALUE_OR_RETURN_BINDER_STATUS(
- aidl2legacy_string_view_String16(opPackageNameAidl));
audio_config_base_t config = VALUE_OR_RETURN_BINDER_STATUS(
aidl2legacy_AudioConfigBase_audio_config_base_t(configAidl));
audio_input_flags_t flags = VALUE_OR_RETURN_BINDER_STATUS(
@@ -536,7 +535,6 @@
RETURN_IF_BINDER_ERROR(
binderStatusFromStatusT(AudioValidator::validateAudioAttributes(attr, "68953950")));
- RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(validateUsage(attr.usage, pid, uid)));
audio_source_t inputSource = attr.source;
if (inputSource == AUDIO_SOURCE_DEFAULT) {
@@ -552,34 +550,42 @@
return binderStatusFromStatusT(BAD_VALUE);
}
- bool updatePid = (pid == -1);
- const uid_t callingUid = IPCThreadState::self()->getCallingUid();
+ // Make sure identity represents the current caller
+ Identity adjIdentity = identity;
+ // TODO b/182392553: refactor or remove
+ bool updatePid = (identity.pid == -1);
+ const uid_t callingUid =IPCThreadState::self()->getCallingUid();
+ const uid_t currentUid = VALUE_OR_RETURN_BINDER_STATUS(aidl2legacy_int32_t_uid_t(identity.uid));
if (!isAudioServerOrMediaServerUid(callingUid)) {
- ALOGW_IF(uid != (uid_t)-1 && uid != callingUid,
- "%s uid %d tried to pass itself off as %d", __FUNCTION__, callingUid, uid);
- uid = callingUid;
+ ALOGW_IF(currentUid != (uid_t)-1 && currentUid != callingUid,
+ "%s uid %d tried to pass itself off as %d", __FUNCTION__, callingUid,
+ currentUid);
+ adjIdentity.uid = VALUE_OR_RETURN_BINDER_STATUS(legacy2aidl_uid_t_int32_t(callingUid));
updatePid = true;
}
if (updatePid) {
- const pid_t callingPid = IPCThreadState::self()->getCallingPid();
- ALOGW_IF(pid != (pid_t)-1 && pid != callingPid,
+ const int32_t callingPid = VALUE_OR_RETURN_BINDER_STATUS(legacy2aidl_pid_t_int32_t(
+ IPCThreadState::self()->getCallingPid()));
+ ALOGW_IF(identity.pid != -1 && identity.pid != callingPid,
"%s uid %d pid %d tried to pass itself off as pid %d",
- __func__, callingUid, callingPid, pid);
- pid = callingPid;
+ __func__, adjIdentity.uid, callingPid, identity.pid);
+ adjIdentity.pid = callingPid;
}
+ RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(validateUsage(attr.usage, adjIdentity)));
+
// check calling permissions.
// Capturing from FM_TUNER source is controlled by captureTunerAudioInputAllowed() and
// captureAudioOutputAllowed() (deprecated) as this does not affect users privacy
// as does capturing from an actual microphone.
- if (!(recordingAllowed(opPackageName, pid, uid) || attr.source == AUDIO_SOURCE_FM_TUNER)) {
- ALOGE("%s permission denied: recording not allowed for uid %d pid %d",
- __func__, uid, pid);
+ if (!(recordingAllowed(adjIdentity) || attr.source == AUDIO_SOURCE_FM_TUNER)) {
+ ALOGE("%s permission denied: recording not allowed for %s",
+ __func__, adjIdentity.toString().c_str());
return binderStatusFromStatusT(PERMISSION_DENIED);
}
- bool canCaptureOutput = captureAudioOutputAllowed(pid, uid);
+ bool canCaptureOutput = captureAudioOutputAllowed(adjIdentity);
if ((inputSource == AUDIO_SOURCE_VOICE_UPLINK ||
inputSource == AUDIO_SOURCE_VOICE_DOWNLINK ||
inputSource == AUDIO_SOURCE_VOICE_CALL ||
@@ -589,12 +595,12 @@
}
if (inputSource == AUDIO_SOURCE_FM_TUNER
- && !captureTunerAudioInputAllowed(pid, uid)
+ && !captureTunerAudioInputAllowed(adjIdentity)
&& !canCaptureOutput) {
return binderStatusFromStatusT(PERMISSION_DENIED);
}
- bool canCaptureHotword = captureHotwordAllowed(opPackageName, pid, uid);
+ bool canCaptureHotword = captureHotwordAllowed(adjIdentity);
if ((inputSource == AUDIO_SOURCE_HOTWORD) && !canCaptureHotword) {
return binderStatusFromStatusT(PERMISSION_DENIED);
}
@@ -602,7 +608,7 @@
if (((flags & AUDIO_INPUT_FLAG_HW_HOTWORD) != 0)
&& !canCaptureHotword) {
ALOGE("%s: permission denied: hotword mode not allowed"
- " for uid %d pid %d", __func__, uid, pid);
+ " for uid %d pid %d", __func__, adjIdentity.uid, adjIdentity.pid);
return binderStatusFromStatusT(PERMISSION_DENIED);
}
@@ -615,10 +621,11 @@
{
AutoCallerClear acc;
// the audio_in_acoustics_t parameter is ignored by get_input()
- status = mAudioPolicyManager->getInputForAttr(&attr, &input, riid, session, uid,
- &config,
+ status = mAudioPolicyManager->getInputForAttr(&attr, &input, riid, session,
+ adjIdentity, &config,
flags, &selectedDeviceId,
&inputType, &portId);
+
}
audioPolicyEffects = mAudioPolicyEffects;
@@ -639,7 +646,7 @@
}
break;
case AudioPolicyInterface::API_INPUT_MIX_EXT_POLICY_REROUTE:
- if (!modifyAudioRoutingAllowed(pid, uid)) {
+ if (!modifyAudioRoutingAllowed(adjIdentity)) {
ALOGE("getInputForAttr() permission denied: modify audio routing not allowed");
status = PERMISSION_DENIED;
}
@@ -659,8 +666,8 @@
return binderStatusFromStatusT(status);
}
- sp<AudioRecordClient> client = new AudioRecordClient(attr, input, uid, pid, session, portId,
- selectedDeviceId, opPackageName,
+ sp<AudioRecordClient> client = new AudioRecordClient(attr, input, session, portId,
+ selectedDeviceId, adjIdentity,
canCaptureOutput, canCaptureHotword);
mAudioRecordClients.add(portId, client);
}
@@ -711,12 +718,15 @@
client = mAudioRecordClients.valueAt(index);
}
+ std::stringstream msg;
+ msg << "Audio recording on session " << client->session;
+
// check calling permissions
- if (!(startRecording(client->opPackageName, client->pid, client->uid,
- client->attributes.source)
+ if (!(startRecording(client->identity, String16(msg.str().c_str()),
+ client->attributes.source)
|| client->attributes.source == AUDIO_SOURCE_FM_TUNER)) {
- ALOGE("%s permission denied: recording not allowed for uid %d pid %d",
- __func__, client->uid, client->pid);
+ ALOGE("%s permission denied: recording not allowed for identity %s",
+ __func__, client->identity.toString().c_str());
return binderStatusFromStatusT(PERMISSION_DENIED);
}
@@ -760,11 +770,13 @@
item->setCString(kAudioPolicyRqstSrc,
toString(client->attributes.source).c_str());
item->setInt32(kAudioPolicyRqstSession, client->session);
- if (client->opPackageName.size() != 0) {
+ if (client->identity.packageName.has_value() &&
+ client->identity.packageName.value().size() != 0) {
item->setCString(kAudioPolicyRqstPkg,
- std::string(String8(client->opPackageName).string()).c_str());
+ client->identity.packageName.value().c_str());
} else {
- item->setCString(kAudioPolicyRqstPkg, std::to_string(client->uid).c_str());
+ item->setCString(kAudioPolicyRqstPkg,
+ std::to_string(client->identity.uid).c_str());
}
item->setCString(
kAudioPolicyRqstDevice, getDeviceTypeStrForPortId(client->deviceId).c_str());
@@ -780,12 +792,13 @@
item->setCString(kAudioPolicyActiveSrc,
toString(other->attributes.source).c_str());
item->setInt32(kAudioPolicyActiveSession, other->session);
- if (other->opPackageName.size() != 0) {
+ if (other->identity.packageName.has_value() &&
+ other->identity.packageName.value().size() != 0) {
item->setCString(kAudioPolicyActivePkg,
- std::string(String8(other->opPackageName).string()).c_str());
+ other->identity.packageName.value().c_str());
} else {
- item->setCString(kAudioPolicyRqstPkg,
- std::to_string(other->uid).c_str());
+ item->setCString(kAudioPolicyRqstPkg, std::to_string(
+ other->identity.uid).c_str());
}
item->setCString(kAudioPolicyActiveDevice,
getDeviceTypeStrForPortId(other->deviceId).c_str());
@@ -801,8 +814,7 @@
client->active = false;
client->startTimeNs = 0;
updateUidStates_l();
- finishRecording(client->opPackageName, client->uid,
- client->attributes.source);
+ finishRecording(client->identity, client->attributes.source);
}
return binderStatusFromStatusT(status);
@@ -831,8 +843,7 @@
updateUidStates_l();
// finish the recording app op
- finishRecording(client->opPackageName, client->uid,
- client->attributes.source);
+ finishRecording(client->identity, client->attributes.source);
AutoCallerClear acc;
return binderStatusFromStatusT(mAudioPolicyManager->stopInput(portId));
}
@@ -1629,15 +1640,15 @@
bool needCaptureMediaOutput = std::any_of(mixes.begin(), mixes.end(), [](auto& mix) {
return mix.mAllowPrivilegedMediaPlaybackCapture; });
- const uid_t callingUid = IPCThreadState::self()->getCallingUid();
- const pid_t callingPid = IPCThreadState::self()->getCallingPid();
+ const Identity identity = getCallingIdentity();
- if (needCaptureMediaOutput && !captureMediaOutputAllowed(callingPid, callingUid)) {
+
+ if (needCaptureMediaOutput && !captureMediaOutputAllowed(identity)) {
return binderStatusFromStatusT(PERMISSION_DENIED);
}
if (needCaptureVoiceCommunicationOutput &&
- !captureVoiceCommunicationOutputAllowed(callingPid, callingUid)) {
+ !captureVoiceCommunicationOutputAllowed(identity)) {
return binderStatusFromStatusT(PERMISSION_DENIED);
}
@@ -1801,8 +1812,7 @@
return Status::ok();
}
-Status AudioPolicyService::getSurroundFormats(
- bool reported, media::Int* count,
+Status AudioPolicyService::getSurroundFormats(media::Int* count,
std::vector<media::audio::common::AudioFormat>* formats,
std::vector<bool>* formatsEnabled) {
unsigned int numSurroundFormats = VALUE_OR_RETURN_BINDER_STATUS(
@@ -1821,7 +1831,7 @@
AutoCallerClear acc;
RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
mAudioPolicyManager->getSurroundFormats(&numSurroundFormats, surroundFormats.get(),
- surroundFormatsEnabled.get(), reported)));
+ surroundFormatsEnabled.get())));
numSurroundFormatsReq = std::min(numSurroundFormats, numSurroundFormatsReq);
RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
convertRange(surroundFormats.get(), surroundFormats.get() + numSurroundFormatsReq,
@@ -1834,6 +1844,32 @@
return Status::ok();
}
+Status AudioPolicyService::getReportedSurroundFormats(
+ media::Int* count, std::vector<media::audio::common::AudioFormat>* formats) {
+ unsigned int numSurroundFormats = VALUE_OR_RETURN_BINDER_STATUS(
+ convertIntegral<unsigned int>(count->value));
+ if (numSurroundFormats > MAX_ITEMS_PER_LIST) {
+ numSurroundFormats = MAX_ITEMS_PER_LIST;
+ }
+ unsigned int numSurroundFormatsReq = numSurroundFormats;
+ std::unique_ptr<audio_format_t[]>surroundFormats(new audio_format_t[numSurroundFormats]);
+
+ if (mAudioPolicyManager == NULL) {
+ return binderStatusFromStatusT(NO_INIT);
+ }
+ Mutex::Autolock _l(mLock);
+ AutoCallerClear acc;
+ RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
+ mAudioPolicyManager->getReportedSurroundFormats(
+ &numSurroundFormats, surroundFormats.get())));
+ numSurroundFormatsReq = std::min(numSurroundFormats, numSurroundFormatsReq);
+ RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
+ convertRange(surroundFormats.get(), surroundFormats.get() + numSurroundFormatsReq,
+ std::back_inserter(*formats), legacy2aidl_audio_format_t_AudioFormat)));
+ count->value = VALUE_OR_RETURN_BINDER_STATUS(convertIntegral<uint32_t>(numSurroundFormats));
+ return Status::ok();
+}
+
Status AudioPolicyService::getHwOffloadEncodingFormatsSupportedForA2DP(
std::vector<media::audio::common::AudioFormat>* _aidl_return) {
std::vector<audio_format_t> formats;
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index 90ad81e..4ffa9cc 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -595,23 +595,24 @@
for (size_t i =0; i < mAudioRecordClients.size(); i++) {
sp<AudioRecordClient> current = mAudioRecordClients[i];
+ uid_t currentUid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(current->identity.uid));
if (!current->active || (!isVirtualSource(current->attributes.source)
- && isUserSensorPrivacyEnabledForUid(current->uid))) {
+ && isUserSensorPrivacyEnabledForUid(currentUid))) {
continue;
}
- app_state_t appState = apmStatFromAmState(mUidPolicy->getUidState(current->uid));
+ app_state_t appState = apmStatFromAmState(mUidPolicy->getUidState(currentUid));
// clients which app is in IDLE state are not eligible for top active or
// latest active
if (appState == APP_STATE_IDLE) {
continue;
}
- bool isAccessibility = mUidPolicy->isA11yUid(current->uid);
+ bool isAccessibility = mUidPolicy->isA11yUid(currentUid);
// Clients capturing for Accessibility services or virtual sources are not considered
// for top or latest active to avoid masking regular clients started before
if (!isAccessibility && !isVirtualSource(current->attributes.source)) {
- bool isAssistant = mUidPolicy->isAssistantUid(current->uid);
+ bool isAssistant = mUidPolicy->isAssistantUid(currentUid);
bool isPrivacySensitive =
(current->attributes.flags & AUDIO_FLAG_CAPTURE_PRIVATE) != 0;
@@ -639,9 +640,11 @@
// if audio mode is IN_COMMUNICATION, make sure the audio mode owner
// is marked latest sensitive active even if another app qualifies.
if (current->startTimeNs > latestSensitiveStartNs
- || (isInCommunication && current->uid == mPhoneStateOwnerUid)) {
+ || (isInCommunication && currentUid == mPhoneStateOwnerUid)) {
if (!isInCommunication || latestSensitiveActiveOrComm == nullptr
- || latestSensitiveActiveOrComm->uid != mPhoneStateOwnerUid) {
+ || VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(
+ latestSensitiveActiveOrComm->identity.uid))
+ != mPhoneStateOwnerUid) {
latestSensitiveActiveOrComm = current;
latestSensitiveStartNs = current->startTimeNs;
}
@@ -658,7 +661,7 @@
if (current->attributes.source != AUDIO_SOURCE_HOTWORD) {
onlyHotwordActive = false;
}
- if (current->uid == mPhoneStateOwnerUid) {
+ if (currentUid == mPhoneStateOwnerUid) {
isPhoneStateOwnerActive = true;
}
}
@@ -674,7 +677,9 @@
} else if (latestSensitiveActiveOrComm != nullptr) {
// if audio mode is IN_COMMUNICATION, favor audio mode owner over an app with
// foreground UI in case both are capturing with privacy sensitive flag.
- if (isInCommunication && latestSensitiveActiveOrComm->uid == mPhoneStateOwnerUid) {
+ uid_t latestActiveUid = VALUE_OR_FATAL(
+ aidl2legacy_int32_t_uid_t(latestSensitiveActiveOrComm->identity.uid));
+ if (isInCommunication && latestActiveUid == mPhoneStateOwnerUid) {
topSensitiveActive = latestSensitiveActiveOrComm;
topSensitiveStartNs = latestSensitiveStartNs;
}
@@ -692,20 +697,25 @@
for (size_t i =0; i < mAudioRecordClients.size(); i++) {
sp<AudioRecordClient> current = mAudioRecordClients[i];
+ uid_t currentUid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(
+ current->identity.uid));
if (!current->active) {
continue;
}
audio_source_t source = current->attributes.source;
- bool isTopOrLatestActive = topActive == nullptr ? false : current->uid == topActive->uid;
- bool isTopOrLatestSensitive = topSensitiveActive == nullptr ?
- false : current->uid == topSensitiveActive->uid;
+ bool isTopOrLatestActive = topActive == nullptr ? false :
+ current->identity.uid == topActive->identity.uid;
+ bool isTopOrLatestSensitive = topSensitiveActive == nullptr ? false :
+ current->identity.uid == topSensitiveActive->identity.uid;
auto canCaptureIfInCallOrCommunication = [&](const auto &recordClient) REQUIRES(mLock) {
+ uid_t recordUid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(
+ recordClient->identity.uid));
bool canCaptureCall = recordClient->canCaptureOutput;
bool canCaptureCommunication = recordClient->canCaptureOutput
|| !isPhoneStateOwnerActive
- || recordClient->uid == mPhoneStateOwnerUid;
+ || recordUid == mPhoneStateOwnerUid;
return !(isInCall && !canCaptureCall)
&& !(isInCommunication && !canCaptureCommunication);
};
@@ -724,10 +734,10 @@
if (isVirtualSource(source)) {
// Allow capture for virtual (remote submix, call audio TX or RX...) sources
allowCapture = true;
- } else if (isUserSensorPrivacyEnabledForUid(current->uid)) {
+ } else if (isUserSensorPrivacyEnabledForUid(currentUid)) {
// If sensor privacy is enabled, don't allow capture
allowCapture = false;
- } else if (mUidPolicy->isAssistantUid(current->uid)) {
+ } else if (mUidPolicy->isAssistantUid(currentUid)) {
// For assistant allow capture if:
// An accessibility service is on TOP or a RTT call is active
// AND the source is VOICE_RECOGNITION or HOTWORD
@@ -747,7 +757,7 @@
allowCapture = true;
}
}
- } else if (mUidPolicy->isA11yUid(current->uid)) {
+ } else if (mUidPolicy->isA11yUid(currentUid)) {
// For accessibility service allow capture if:
// The assistant is not on TOP
// AND there is no active privacy sensitive capture or call
@@ -773,7 +783,7 @@
&& canCaptureIfInCallOrCommunication(current)) {
allowCapture = true;
}
- } else if (mUidPolicy->isCurrentImeUid(current->uid)) {
+ } else if (mUidPolicy->isCurrentImeUid(currentUid)) {
// For current InputMethodService allow capture if:
// A RTT call is active AND the source is VOICE_RECOGNITION
if (rttCallActive && source == AUDIO_SOURCE_VOICE_RECOGNITION) {
@@ -781,7 +791,7 @@
}
}
setAppState_l(current->portId,
- allowCapture ? apmStatFromAmState(mUidPolicy->getUidState(current->uid)) :
+ allowCapture ? apmStatFromAmState(mUidPolicy->getUidState(currentUid)) :
APP_STATE_IDLE);
}
}
@@ -925,6 +935,7 @@
case TRANSACTION_registerPolicyMixes:
case TRANSACTION_setMasterMono:
case TRANSACTION_getSurroundFormats:
+ case TRANSACTION_getReportedSurroundFormats:
case TRANSACTION_setSurroundFormatEnabled:
case TRANSACTION_setAssistantUid:
case TRANSACTION_setA11yServicesUids:
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index a11b2cc..145ba06 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -38,6 +38,8 @@
#include "CaptureStateNotifier.h"
#include <AudioPolicyInterface.h>
#include <android/hardware/BnSensorPrivacyListener.h>
+#include <android/media/permission/Identity.h>
+
#include <unordered_map>
namespace android {
@@ -79,15 +81,16 @@
media::AudioPolicyForcedConfig* _aidl_return) override;
binder::Status getOutput(media::AudioStreamType stream, int32_t* _aidl_return) override;
binder::Status getOutputForAttr(const media::AudioAttributesInternal& attr, int32_t session,
- int32_t pid, int32_t uid, const media::AudioConfig& config,
+ const media::permission::Identity &identity,
+ const media::AudioConfig& config,
int32_t flags, int32_t selectedDeviceId,
media::GetOutputForAttrResponse* _aidl_return) override;
binder::Status startOutput(int32_t portId) override;
binder::Status stopOutput(int32_t portId) override;
binder::Status releaseOutput(int32_t portId) override;
binder::Status getInputForAttr(const media::AudioAttributesInternal& attr, int32_t input,
- int32_t riid, int32_t session, int32_t pid, int32_t uid,
- const std::string& opPackageName,
+ int32_t riid, int32_t session,
+ const media::permission::Identity &identity,
const media::AudioConfigBase& config, int32_t flags,
int32_t selectedDeviceId,
media::GetInputForAttrResponse* _aidl_return) override;
@@ -182,9 +185,11 @@
binder::Status getMasterMono(bool* _aidl_return) override;
binder::Status getStreamVolumeDB(media::AudioStreamType stream, int32_t index, int32_t device,
float* _aidl_return) override;
- binder::Status getSurroundFormats(bool reported, media::Int* count,
+ binder::Status getSurroundFormats(media::Int* count,
std::vector<media::audio::common::AudioFormat>* formats,
std::vector<bool>* formatsEnabled) override;
+ binder::Status getReportedSurroundFormats(
+ media::Int* count, std::vector<media::audio::common::AudioFormat>* formats) override;
binder::Status getHwOffloadEncodingFormatsSupportedForA2DP(
std::vector<media::audio::common::AudioFormat>* _aidl_return) override;
binder::Status setSurroundFormatEnabled(media::audio::common::AudioFormat audioFormat,
@@ -339,7 +344,7 @@
bool isSupportedSystemUsage(audio_usage_t usage);
status_t validateUsage(audio_usage_t usage);
- status_t validateUsage(audio_usage_t usage, pid_t pid, uid_t uid);
+ status_t validateUsage(audio_usage_t usage, const media::permission::Identity& identity);
bool isUserSensorPrivacyEnabledForUid(uid_t uid);
@@ -784,18 +789,18 @@
class AudioClient : public virtual RefBase {
public:
AudioClient(const audio_attributes_t attributes,
- const audio_io_handle_t io, uid_t uid, pid_t pid,
+ const audio_io_handle_t io,
+ const media::permission::Identity& identity,
const audio_session_t session, audio_port_handle_t portId,
const audio_port_handle_t deviceId) :
- attributes(attributes), io(io), uid(uid), pid(pid),
+ attributes(attributes), io(io), identity(identity),
session(session), portId(portId), deviceId(deviceId), active(false) {}
~AudioClient() override = default;
const audio_attributes_t attributes; // source, flags ...
const audio_io_handle_t io; // audio HAL stream IO handle
- const uid_t uid; // client UID
- const pid_t pid; // client PID
+ const media::permission::Identity& identity; //client identity
const audio_session_t session; // audio session ID
const audio_port_handle_t portId;
const audio_port_handle_t deviceId; // selected input device port ID
@@ -808,16 +813,17 @@
class AudioRecordClient : public AudioClient {
public:
AudioRecordClient(const audio_attributes_t attributes,
- const audio_io_handle_t io, uid_t uid, pid_t pid,
+ const audio_io_handle_t io,
const audio_session_t session, audio_port_handle_t portId,
- const audio_port_handle_t deviceId, const String16& opPackageName,
+ const audio_port_handle_t deviceId,
+ const media::permission::Identity& identity,
bool canCaptureOutput, bool canCaptureHotword) :
- AudioClient(attributes, io, uid, pid, session, portId, deviceId),
- opPackageName(opPackageName), startTimeNs(0),
+ AudioClient(attributes, io, identity,
+ session, portId, deviceId), identity(identity), startTimeNs(0),
canCaptureOutput(canCaptureOutput), canCaptureHotword(canCaptureHotword) {}
~AudioRecordClient() override = default;
- const String16 opPackageName; // client package name
+ const media::permission::Identity identity; // identity of client
nsecs_t startTimeNs;
const bool canCaptureOutput;
const bool canCaptureHotword;
@@ -829,10 +835,11 @@
class AudioPlaybackClient : public AudioClient {
public:
AudioPlaybackClient(const audio_attributes_t attributes,
- const audio_io_handle_t io, uid_t uid, pid_t pid,
+ const audio_io_handle_t io, media::permission::Identity identity,
const audio_session_t session, audio_port_handle_t portId,
audio_port_handle_t deviceId, audio_stream_type_t stream) :
- AudioClient(attributes, io, uid, pid, session, portId, deviceId), stream(stream) {}
+ AudioClient(attributes, io, identity, session, portId,
+ deviceId), stream(stream) {}
~AudioPlaybackClient() override = default;
const audio_stream_type_t stream;
diff --git a/services/audiopolicy/tests/Android.bp b/services/audiopolicy/tests/Android.bp
index d10fcb9..f480210 100644
--- a/services/audiopolicy/tests/Android.bp
+++ b/services/audiopolicy/tests/Android.bp
@@ -25,6 +25,7 @@
"libmedia_helper",
"libutils",
"libxml2",
+ "media_permission-aidl-cpp",
],
static_libs: [
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index a8ede90..8f12ecf 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -25,6 +25,7 @@
#define LOG_TAG "APM_Test"
#include <Serializer.h>
#include <android-base/file.h>
+#include <android/media/permission/Identity.h>
#include <media/AudioPolicy.h>
#include <media/PatchBuilder.h>
#include <media/RecordingActivityTracker.h>
@@ -39,6 +40,7 @@
using namespace android;
using testing::UnorderedElementsAre;
+using media::permission::Identity;
TEST(AudioPolicyManagerTestInit, EngineFailure) {
AudioPolicyTestClient client;
@@ -214,8 +216,11 @@
if (!portId) portId = &localPortId;
*portId = AUDIO_PORT_HANDLE_NONE;
AudioPolicyInterface::output_type_t outputType;
+ // TODO b/182392769: use identity util
+ Identity i = Identity();
+ i.uid = 0;
ASSERT_EQ(OK, mManager->getOutputForAttr(
- &attr, output, AUDIO_SESSION_NONE, &stream, 0 /*uid*/, &config, &flags,
+ &attr, output, AUDIO_SESSION_NONE, &stream, i, &config, &flags,
selectedDeviceId, portId, {}, &outputType));
ASSERT_NE(AUDIO_PORT_HANDLE_NONE, *portId);
ASSERT_NE(AUDIO_IO_HANDLE_NONE, *output);
@@ -239,8 +244,11 @@
if (!portId) portId = &localPortId;
*portId = AUDIO_PORT_HANDLE_NONE;
AudioPolicyInterface::input_type_t inputType;
+ // TODO b/182392769: use identity util
+ Identity i = Identity();
+ i.uid = 0;
ASSERT_EQ(OK, mManager->getInputForAttr(
- &attr, &input, riid, AUDIO_SESSION_NONE, 0 /*uid*/, &config, flags,
+ &attr, &input, riid, AUDIO_SESSION_NONE, i, &config, flags,
selectedDeviceId, &inputType, portId));
ASSERT_NE(AUDIO_PORT_HANDLE_NONE, *portId);
}
@@ -797,7 +805,8 @@
protected:
void SetUp() override;
std::string getConfigFile() override { return sTvConfig; }
- std::map<audio_format_t, bool> getSurroundFormatsHelper(bool reported);
+ std::map<audio_format_t, bool> getSurroundFormatsHelper();
+ std::vector<audio_format_t> getReportedSurroundFormatsHelper();
std::unordered_set<audio_format_t> getFormatsFromPorts();
AudioPolicyManagerTestClient* getClient() override {
return new AudioPolicyManagerTestClientForHdmi;
@@ -828,12 +837,12 @@
}
std::map<audio_format_t, bool>
- AudioPolicyManagerTestForHdmi::getSurroundFormatsHelper(bool reported) {
+ AudioPolicyManagerTestForHdmi::getSurroundFormatsHelper() {
unsigned int numSurroundFormats = 0;
std::map<audio_format_t, bool> surroundFormatsMap;
status_t ret = mManager->getSurroundFormats(
&numSurroundFormats, nullptr /* surroundFormats */,
- nullptr /* surroundFormatsEnabled */, reported);
+ nullptr /* surroundFormatsEnabled */);
EXPECT_EQ(NO_ERROR, ret);
if (ret != NO_ERROR) {
return surroundFormatsMap;
@@ -843,7 +852,7 @@
bool surroundFormatsEnabled[numSurroundFormats];
memset(surroundFormatsEnabled, 0, sizeof(bool) * numSurroundFormats);
ret = mManager->getSurroundFormats(
- &numSurroundFormats, surroundFormats, surroundFormatsEnabled, reported);
+ &numSurroundFormats, surroundFormats, surroundFormatsEnabled);
EXPECT_EQ(NO_ERROR, ret);
if (ret != NO_ERROR) {
return surroundFormatsMap;
@@ -854,6 +863,28 @@
return surroundFormatsMap;
}
+std::vector<audio_format_t> AudioPolicyManagerTestForHdmi::getReportedSurroundFormatsHelper() {
+ unsigned int numSurroundFormats = 0;
+ std::vector<audio_format_t> surroundFormatsVector;
+ status_t ret = mManager->getReportedSurroundFormats(
+ &numSurroundFormats, nullptr /* surroundFormats */);
+ EXPECT_EQ(NO_ERROR, ret);
+ if (ret != NO_ERROR) {
+ return surroundFormatsVector;
+ }
+ audio_format_t surroundFormats[numSurroundFormats];
+ memset(surroundFormats, 0, sizeof(audio_format_t) * numSurroundFormats);
+ ret = mManager->getReportedSurroundFormats(&numSurroundFormats, surroundFormats);
+ EXPECT_EQ(NO_ERROR, ret);
+ if (ret != NO_ERROR) {
+ return surroundFormatsVector;
+ }
+ for (const auto &surroundFormat : surroundFormats) {
+ surroundFormatsVector.push_back(surroundFormat);
+ }
+ return surroundFormatsVector;
+}
+
std::unordered_set<audio_format_t>
AudioPolicyManagerTestForHdmi::getFormatsFromPorts() {
uint32_t numPorts = 0;
@@ -884,7 +915,7 @@
TEST_F(AudioPolicyManagerTestForHdmi, GetSurroundFormatsReturnsSupportedFormats) {
mManager->setForceUse(
AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND, AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS);
- auto surroundFormats = getSurroundFormatsHelper(false /*reported*/);
+ auto surroundFormats = getSurroundFormatsHelper();
ASSERT_EQ(1, surroundFormats.count(AUDIO_FORMAT_E_AC3));
}
@@ -896,19 +927,19 @@
status_t ret =
mManager->setSurroundFormatEnabled(AUDIO_FORMAT_E_AC3, false /*enabled*/);
ASSERT_EQ(NO_ERROR, ret);
- auto surroundFormats = getSurroundFormatsHelper(false /*reported*/);
+ auto surroundFormats = getSurroundFormatsHelper();
ASSERT_EQ(1, surroundFormats.count(AUDIO_FORMAT_E_AC3));
ASSERT_FALSE(surroundFormats[AUDIO_FORMAT_E_AC3]);
ret = mManager->setSurroundFormatEnabled(AUDIO_FORMAT_E_AC3, true /*enabled*/);
ASSERT_EQ(NO_ERROR, ret);
- surroundFormats = getSurroundFormatsHelper(false /*reported*/);
+ surroundFormats = getSurroundFormatsHelper();
ASSERT_EQ(1, surroundFormats.count(AUDIO_FORMAT_E_AC3));
ASSERT_TRUE(surroundFormats[AUDIO_FORMAT_E_AC3]);
ret = mManager->setSurroundFormatEnabled(AUDIO_FORMAT_E_AC3, false /*enabled*/);
ASSERT_EQ(NO_ERROR, ret);
- surroundFormats = getSurroundFormatsHelper(false /*reported*/);
+ surroundFormats = getSurroundFormatsHelper();
ASSERT_EQ(1, surroundFormats.count(AUDIO_FORMAT_E_AC3));
ASSERT_FALSE(surroundFormats[AUDIO_FORMAT_E_AC3]);
}
@@ -931,8 +962,8 @@
GetReportedSurroundFormatsReturnsHdmiReportedFormats) {
mManager->setForceUse(
AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND, AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS);
- auto surroundFormats = getSurroundFormatsHelper(true /*reported*/);
- ASSERT_EQ(1, surroundFormats.count(AUDIO_FORMAT_E_AC3));
+ auto surroundFormats = getReportedSurroundFormatsHelper();
+ ASSERT_EQ(1, std::count(surroundFormats.begin(), surroundFormats.end(), AUDIO_FORMAT_E_AC3));
}
TEST_F(AudioPolicyManagerTestForHdmi,
@@ -942,13 +973,13 @@
status_t ret = mManager->setSurroundFormatEnabled(AUDIO_FORMAT_E_AC3, false /*enabled*/);
ASSERT_EQ(NO_ERROR, ret);
- auto surroundFormats = getSurroundFormatsHelper(true /*reported*/);
- ASSERT_EQ(1, surroundFormats.count(AUDIO_FORMAT_E_AC3));
+ auto surroundFormats = getReportedSurroundFormatsHelper();
+ ASSERT_EQ(1, std::count(surroundFormats.begin(), surroundFormats.end(), AUDIO_FORMAT_E_AC3));
ret = mManager->setSurroundFormatEnabled(AUDIO_FORMAT_E_AC3, true /*enabled*/);
ASSERT_EQ(NO_ERROR, ret);
- surroundFormats = getSurroundFormatsHelper(true /*reported*/);
- ASSERT_EQ(1, surroundFormats.count(AUDIO_FORMAT_E_AC3));
+ surroundFormats = getReportedSurroundFormatsHelper();
+ ASSERT_EQ(1, std::count(surroundFormats.begin(), surroundFormats.end(), AUDIO_FORMAT_E_AC3));
}
class AudioPolicyManagerTestDPNoRemoteSubmixModule : public AudioPolicyManagerTestDynamicPolicy {
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp
index e9f95cb..a0b35a8 100644
--- a/services/camera/libcameraservice/Android.bp
+++ b/services/camera/libcameraservice/Android.bp
@@ -143,15 +143,19 @@
"android.hardware.camera.provider@2.4",
"android.hardware.camera.provider@2.5",
"android.hardware.camera.provider@2.6",
+ "android.hardware.camera.provider@2.7",
"android.hardware.camera.device@3.2",
"android.hardware.camera.device@3.3",
"android.hardware.camera.device@3.4",
"android.hardware.camera.device@3.5",
- "android.hardware.camera.device@3.6"
+ "android.hardware.camera.device@3.6",
+ "android.hardware.camera.device@3.7",
+ "media_permission-aidl-cpp",
],
static_libs: [
"libbinderthreadstateutils",
+ "media_permission-aidl-cpp",
],
export_shared_lib_headers: [
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 1234dfd..706197e 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -805,6 +805,7 @@
case CAMERA_DEVICE_API_VERSION_3_4:
case CAMERA_DEVICE_API_VERSION_3_5:
case CAMERA_DEVICE_API_VERSION_3_6:
+ case CAMERA_DEVICE_API_VERSION_3_7:
if (effectiveApiLevel == API_1) { // Camera1 API route
sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
*client = new Camera2Client(cameraService, tmp, packageName, featureId,
@@ -2271,6 +2272,7 @@
case CAMERA_DEVICE_API_VERSION_3_4:
case CAMERA_DEVICE_API_VERSION_3_5:
case CAMERA_DEVICE_API_VERSION_3_6:
+ case CAMERA_DEVICE_API_VERSION_3_7:
ALOGV("%s: Camera id %s uses HAL3.2 or newer, supports api1/api2 directly",
__FUNCTION__, id.string());
*isSupported = true;
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index e062c14..8164df0 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -29,7 +29,6 @@
#include "Parameters.h"
#include "system/camera.h"
-#include "hardware/camera_common.h"
#include <android/hardware/ICamera.h>
#include <media/MediaProfiles.h>
#include <media/mediarecorder.h>
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
index 0701b6f..9fdc727 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
@@ -237,7 +237,7 @@
if (mInputStreamId == NO_STREAM) {
res = device->createInputStream(params.fastInfo.maxZslSize.width,
params.fastInfo.maxZslSize.height, HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
- &mInputStreamId);
+ /*isMultiResolution*/false, &mInputStreamId);
if (res != OK) {
ALOGE("%s: Camera %d: Can't create input stream: "
"%s (%d)", __FUNCTION__, client->getCameraId(),
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index d47014e..8cccbb1 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -584,7 +584,7 @@
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
}
- hardware::camera::device::V3_4::StreamConfiguration streamConfiguration;
+ hardware::camera::device::V3_7::StreamConfiguration streamConfiguration;
bool earlyExit = false;
metadataGetter getMetadata = [this](const String8 &id) {return mDevice->infoPhysical(id);};
std::vector<std::string> physicalCameraIds;
@@ -738,6 +738,7 @@
bool isShared = outputConfiguration.isShared();
String8 physicalCameraId = String8(outputConfiguration.getPhysicalCameraId());
bool deferredConsumerOnly = deferredConsumer && numBufferProducers == 0;
+ bool isMultiResolution = outputConfiguration.isMultiResolution();
res = SessionConfigurationUtils::checkSurfaceType(numBufferProducers, deferredConsumer,
outputConfiguration.getSurfaceType());
@@ -809,7 +810,7 @@
streamInfo.height, streamInfo.format,
static_cast<camera_stream_rotation_t>(outputConfiguration.getRotation()),
&streamId, physicalCameraId, &surfaceIds, outputConfiguration.getSurfaceSetID(),
- isShared);
+ isShared, isMultiResolution);
if (err == OK) {
mCompositeStreamMap.add(IInterface::asBinder(surfaces[0]->getIGraphicBufferProducer()),
compositeStream);
@@ -819,7 +820,7 @@
streamInfo.height, streamInfo.format, streamInfo.dataSpace,
static_cast<camera_stream_rotation_t>(outputConfiguration.getRotation()),
&streamId, physicalCameraId, &surfaceIds, outputConfiguration.getSurfaceSetID(),
- isShared);
+ isShared, isMultiResolution);
}
if (err != OK) {
@@ -888,7 +889,7 @@
static_cast<camera_stream_rotation_t>(outputConfiguration.getRotation()),
&streamId, physicalCameraId, &surfaceIds,
outputConfiguration.getSurfaceSetID(), isShared,
- consumerUsage);
+ outputConfiguration.isMultiResolution(), consumerUsage);
if (err != OK) {
res = STATUS_ERROR_FMT(CameraService::ERROR_INVALID_OPERATION,
@@ -943,12 +944,13 @@
}
binder::Status CameraDeviceClient::createInputStream(
- int width, int height, int format,
+ int width, int height, int format, bool isMultiResolution,
/*out*/
int32_t* newStreamId) {
ATRACE_CALL();
- ALOGV("%s (w = %d, h = %d, f = 0x%x)", __FUNCTION__, width, height, format);
+ ALOGV("%s (w = %d, h = %d, f = 0x%x, isMultiResolution %d)", __FUNCTION__,
+ width, height, format, isMultiResolution);
binder::Status res;
if (!(res = checkPidStatus(__FUNCTION__)).isOk()) return res;
@@ -967,7 +969,7 @@
}
int streamId = -1;
- status_t err = mDevice->createInputStream(width, height, format, &streamId);
+ status_t err = mDevice->createInputStream(width, height, format, isMultiResolution, &streamId);
if (err == OK) {
mInputStream.configured = true;
mInputStream.width = width;
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index 5588285..9f7a4af 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -115,6 +115,7 @@
// Create an input stream of width, height, and format.
virtual binder::Status createInputStream(int width, int height, int format,
+ bool isMultiResolution,
/*out*/
int32_t* newStreamId = NULL) override;
diff --git a/services/camera/libcameraservice/api2/CompositeStream.cpp b/services/camera/libcameraservice/api2/CompositeStream.cpp
index 2f8ca6b..515b7f2 100644
--- a/services/camera/libcameraservice/api2/CompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/CompositeStream.cpp
@@ -47,7 +47,7 @@
status_t CompositeStream::createStream(const std::vector<sp<Surface>>& consumers,
bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
camera_stream_rotation_t rotation, int * id, const String8& physicalCameraId,
- std::vector<int> * surfaceIds, int streamSetId, bool isShared) {
+ std::vector<int> * surfaceIds, int streamSetId, bool isShared, bool isMultiResolution) {
if (hasDeferredConsumer) {
ALOGE("%s: Deferred consumers not supported in case of composite streams!",
__FUNCTION__);
@@ -66,6 +66,12 @@
return BAD_VALUE;
}
+ if (isMultiResolution) {
+ ALOGE("%s: Multi-resolution output not supported in case of composite streams!",
+ __FUNCTION__);
+ return BAD_VALUE;
+ }
+
return createInternalStreams(consumers, hasDeferredConsumer, width, height, format, rotation, id,
physicalCameraId, surfaceIds, streamSetId, isShared);
}
diff --git a/services/camera/libcameraservice/api2/CompositeStream.h b/services/camera/libcameraservice/api2/CompositeStream.h
index 2a934df..1bf137a 100644
--- a/services/camera/libcameraservice/api2/CompositeStream.h
+++ b/services/camera/libcameraservice/api2/CompositeStream.h
@@ -44,7 +44,7 @@
status_t createStream(const std::vector<sp<Surface>>& consumers,
bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
camera_stream_rotation_t rotation, int *id, const String8& physicalCameraId,
- std::vector<int> *surfaceIds, int streamSetId, bool isShared);
+ std::vector<int> *surfaceIds, int streamSetId, bool isShared, bool isMultiResolution);
status_t deleteStream();
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index 1be46d6..5acbb99 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -166,7 +166,8 @@
const String8& physicalCameraId,
std::vector<int> *surfaceIds = nullptr,
int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID,
- bool isShared = false, uint64_t consumerUsage = 0) = 0;
+ bool isShared = false, bool isMultiResolution = false,
+ uint64_t consumerUsage = 0) = 0;
/**
* Create an output stream of the requested size, format, rotation and
@@ -181,7 +182,8 @@
const String8& physicalCameraId,
std::vector<int> *surfaceIds = nullptr,
int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID,
- bool isShared = false, uint64_t consumerUsage = 0) = 0;
+ bool isShared = false, bool isMultiResolution = false,
+ uint64_t consumerUsage = 0) = 0;
/**
* Create an input stream of width, height, and format.
@@ -189,7 +191,7 @@
* Return value is the stream ID if non-negative and an error if negative.
*/
virtual status_t createInputStream(uint32_t width, uint32_t height,
- int32_t format, /*out*/ int32_t *id) = 0;
+ int32_t format, bool multiResolution, /*out*/ int32_t *id) = 0;
struct StreamInfo {
uint32_t width;
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index e9dcb01..dfe2409 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -20,7 +20,7 @@
#include "CameraProviderManager.h"
-#include <android/hardware/camera/device/3.5/ICameraDevice.h>
+#include <android/hardware/camera/device/3.7/ICameraDevice.h>
#include <algorithm>
#include <chrono>
@@ -28,7 +28,6 @@
#include <dlfcn.h>
#include <future>
#include <inttypes.h>
-#include <hardware/camera_common.h>
#include <android/hidl/manager/1.2/IServiceManager.h>
#include <hidl/ServiceManagement.h>
#include <functional>
@@ -49,7 +48,7 @@
using namespace ::android::hardware::camera::common::V1_0;
using std::literals::chrono_literals::operator""s;
using hardware::camera2::utils::CameraIdAndSessionConfiguration;
-using hardware::camera::provider::V2_6::CameraIdAndStreamCombination;
+using hardware::camera::provider::V2_7::CameraIdAndStreamCombination;
namespace {
const bool kEnableLazyHal(property_get_bool("ro.camera.enableLazyHal", false));
@@ -267,7 +266,7 @@
}
status_t CameraProviderManager::isSessionConfigurationSupported(const std::string& id,
- const hardware::camera::device::V3_4::StreamConfiguration &configuration,
+ const hardware::camera::device::V3_7::StreamConfiguration &configuration,
bool *status /*out*/) const {
std::lock_guard<std::mutex> lock(mInterfaceMutex);
auto deviceInfo = findDeviceInfoLocked(id);
@@ -1302,6 +1301,14 @@
mMinorVersion = 5;
}
}
+ } else {
+ auto cast2_7 = provider::V2_7::ICameraProvider::castFrom(interface);
+ if (cast2_7.isOk()) {
+ sp<provider::V2_7::ICameraProvider> interface2_7 = cast2_7;
+ if (interface2_7 != nullptr) {
+ mMinorVersion = 7;
+ }
+ }
}
// cameraDeviceStatusChange callbacks may be called (and causing new devices added)
@@ -1973,38 +1980,67 @@
// TODO: This might be some other problem
return INVALID_OPERATION;
}
- auto castResult = provider::V2_6::ICameraProvider::castFrom(interface);
- if (castResult.isOk()) {
- sp<provider::V2_6::ICameraProvider> interface_2_6 = castResult;
- if (interface_2_6 != nullptr) {
- Status callStatus;
- auto cb =
- [&isSupported, &callStatus](Status s, bool supported) {
- callStatus = s;
- *isSupported = supported; };
+ auto castResult2_6 = provider::V2_6::ICameraProvider::castFrom(interface);
+ auto castResult2_7 = provider::V2_7::ICameraProvider::castFrom(interface);
+ Status callStatus;
+ auto cb =
+ [&isSupported, &callStatus](Status s, bool supported) {
+ callStatus = s;
+ *isSupported = supported; };
- auto ret = interface_2_6->isConcurrentStreamCombinationSupported(
- halCameraIdsAndStreamCombinations, cb);
- if (ret.isOk()) {
- switch (callStatus) {
- case Status::OK:
- // Expected case, do nothing.
- res = OK;
- break;
- case Status::METHOD_NOT_SUPPORTED:
- res = INVALID_OPERATION;
- break;
- default:
- ALOGE("%s: Session configuration query failed: %d", __FUNCTION__,
- callStatus);
- res = UNKNOWN_ERROR;
- }
- } else {
- ALOGE("%s: Unexpected binder error: %s", __FUNCTION__, ret.description().c_str());
- res = UNKNOWN_ERROR;
- }
- return res;
+ ::android::hardware::Return<void> ret;
+ sp<provider::V2_7::ICameraProvider> interface_2_7;
+ sp<provider::V2_6::ICameraProvider> interface_2_6;
+ if (mMinorVersion >= 7 && castResult2_7.isOk()) {
+ interface_2_7 = castResult2_7;
+ if (interface_2_7 != nullptr) {
+ ret = interface_2_7->isConcurrentStreamCombinationSupported_2_7(
+ halCameraIdsAndStreamCombinations, cb);
}
+ } else if (mMinorVersion == 6 && castResult2_6.isOk()) {
+ interface_2_6 = castResult2_6;
+ if (interface_2_6 != nullptr) {
+ hardware::hidl_vec<provider::V2_6::CameraIdAndStreamCombination>
+ halCameraIdsAndStreamCombinations_2_6;
+ size_t numStreams = halCameraIdsAndStreamCombinations.size();
+ halCameraIdsAndStreamCombinations_2_6.resize(numStreams);
+ for (size_t i = 0; i < numStreams; i++) {
+ auto const& combination = halCameraIdsAndStreamCombinations[i];
+ halCameraIdsAndStreamCombinations_2_6[i].cameraId = combination.cameraId;
+ bool success =
+ SessionConfigurationUtils::convertHALStreamCombinationFromV37ToV34(
+ halCameraIdsAndStreamCombinations_2_6[i].streamConfiguration,
+ combination.streamConfiguration);
+ if (!success) {
+ *isSupported = false;
+ return OK;
+ }
+ }
+ ret = interface_2_6->isConcurrentStreamCombinationSupported(
+ halCameraIdsAndStreamCombinations_2_6, cb);
+ }
+ }
+
+ if (interface_2_7 != nullptr || interface_2_6 != nullptr) {
+ if (ret.isOk()) {
+ switch (callStatus) {
+ case Status::OK:
+ // Expected case, do nothing.
+ res = OK;
+ break;
+ case Status::METHOD_NOT_SUPPORTED:
+ res = INVALID_OPERATION;
+ break;
+ default:
+ ALOGE("%s: Session configuration query failed: %d", __FUNCTION__,
+ callStatus);
+ res = UNKNOWN_ERROR;
+ }
+ } else {
+ ALOGE("%s: Unexpected binder error: %s", __FUNCTION__, ret.description().c_str());
+ res = UNKNOWN_ERROR;
+ }
+ return res;
}
}
// unsupported operation
@@ -2374,7 +2410,7 @@
}
status_t CameraProviderManager::ProviderInfo::DeviceInfo3::isSessionConfigurationSupported(
- const hardware::camera::device::V3_4::StreamConfiguration &configuration,
+ const hardware::camera::device::V3_7::StreamConfiguration &configuration,
bool *status /*out*/) {
const sp<CameraProviderManager::ProviderInfo::DeviceInfo3::InterfaceT> interface =
@@ -2382,19 +2418,37 @@
if (interface == nullptr) {
return DEAD_OBJECT;
}
- auto castResult = device::V3_5::ICameraDevice::castFrom(interface);
- sp<hardware::camera::device::V3_5::ICameraDevice> interface_3_5 = castResult;
- if (interface_3_5 == nullptr) {
- return INVALID_OPERATION;
- }
+ auto castResult_3_5 = device::V3_5::ICameraDevice::castFrom(interface);
+ sp<hardware::camera::device::V3_5::ICameraDevice> interface_3_5 = castResult_3_5;
+ auto castResult_3_7 = device::V3_7::ICameraDevice::castFrom(interface);
+ sp<hardware::camera::device::V3_7::ICameraDevice> interface_3_7 = castResult_3_7;
status_t res;
Status callStatus;
- auto ret = interface_3_5->isStreamCombinationSupported(configuration,
+ ::android::hardware::Return<void> ret;
+ if (interface_3_7 != nullptr) {
+ ret = interface_3_7->isStreamCombinationSupported_3_7(configuration,
[&callStatus, &status] (Status s, bool combStatus) {
callStatus = s;
*status = combStatus;
});
+ } else if (interface_3_5 != nullptr) {
+ hardware::camera::device::V3_4::StreamConfiguration configuration_3_4;
+ bool success = SessionConfigurationUtils::convertHALStreamCombinationFromV37ToV34(
+ configuration_3_4, configuration);
+ if (!success) {
+ *status = false;
+ return OK;
+ }
+
+ ret = interface_3_5->isStreamCombinationSupported(configuration_3_4,
+ [&callStatus, &status] (Status s, bool combStatus) {
+ callStatus = s;
+ *status = combStatus;
+ });
+ } else {
+ return INVALID_OPERATION;
+ }
if (ret.isOk()) {
switch (callStatus) {
case Status::OK:
@@ -2769,7 +2823,7 @@
bool shouldExit = false;
status_t res = OK;
for (auto &cameraIdAndSessionConfig : cameraIdsAndSessionConfigs) {
- hardware::camera::device::V3_4::StreamConfiguration streamConfiguration;
+ hardware::camera::device::V3_7::StreamConfiguration streamConfiguration;
CameraMetadata deviceInfo;
res = getCameraCharacteristicsLocked(cameraIdAndSessionConfig.mCameraId, &deviceInfo);
if (res != OK) {
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index 8727e7f..fa9cc1c 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -33,7 +33,8 @@
#include <android/hardware/camera/provider/2.5/ICameraProvider.h>
#include <android/hardware/camera/provider/2.6/ICameraProviderCallback.h>
#include <android/hardware/camera/provider/2.6/ICameraProvider.h>
-#include <android/hardware/camera/device/3.4/ICameraDeviceSession.h>
+#include <android/hardware/camera/provider/2.7/ICameraProvider.h>
+#include <android/hardware/camera/device/3.7/types.h>
#include <android/hidl/manager/1.0/IServiceNotification.h>
#include <camera/VendorTagDescriptor.h>
@@ -78,6 +79,16 @@
HIDDEN_SECURE_CAMERA
};
+#define CAMERA_DEVICE_API_VERSION_1_0 HARDWARE_DEVICE_API_VERSION(1, 0)
+#define CAMERA_DEVICE_API_VERSION_3_0 HARDWARE_DEVICE_API_VERSION(3, 0)
+#define CAMERA_DEVICE_API_VERSION_3_1 HARDWARE_DEVICE_API_VERSION(3, 1)
+#define CAMERA_DEVICE_API_VERSION_3_2 HARDWARE_DEVICE_API_VERSION(3, 2)
+#define CAMERA_DEVICE_API_VERSION_3_3 HARDWARE_DEVICE_API_VERSION(3, 3)
+#define CAMERA_DEVICE_API_VERSION_3_4 HARDWARE_DEVICE_API_VERSION(3, 4)
+#define CAMERA_DEVICE_API_VERSION_3_5 HARDWARE_DEVICE_API_VERSION(3, 5)
+#define CAMERA_DEVICE_API_VERSION_3_6 HARDWARE_DEVICE_API_VERSION(3, 6)
+#define CAMERA_DEVICE_API_VERSION_3_7 HARDWARE_DEVICE_API_VERSION(3, 7)
+
/**
* A manager for all camera providers available on an Android device.
*
@@ -227,7 +238,7 @@
* Check for device support of specific stream combination.
*/
status_t isSessionConfigurationSupported(const std::string& id,
- const hardware::camera::device::V3_4::StreamConfiguration &configuration,
+ const hardware::camera::device::V3_7::StreamConfiguration &configuration,
bool *status /*out*/) const;
/**
@@ -430,7 +441,7 @@
*/
status_t isConcurrentSessionConfigurationSupported(
const hardware::hidl_vec<
- hardware::camera::provider::V2_6::CameraIdAndStreamCombination>
+ hardware::camera::provider::V2_7::CameraIdAndStreamCombination>
&halCameraIdsAndStreamCombinations,
bool *isSupported);
@@ -470,7 +481,7 @@
}
virtual status_t isSessionConfigurationSupported(
- const hardware::camera::device::V3_4::StreamConfiguration &/*configuration*/,
+ const hardware::camera::device::V3_7::StreamConfiguration &/*configuration*/,
bool * /*status*/) {
return INVALID_OPERATION;
}
@@ -529,7 +540,7 @@
virtual status_t getPhysicalCameraCharacteristics(const std::string& physicalCameraId,
CameraMetadata *characteristics) const override;
virtual status_t isSessionConfigurationSupported(
- const hardware::camera::device::V3_4::StreamConfiguration &configuration,
+ const hardware::camera::device::V3_7::StreamConfiguration &configuration,
bool *status /*out*/)
override;
@@ -684,7 +695,7 @@
status_t convertToHALStreamCombinationAndCameraIdsLocked(
const std::vector<hardware::camera2::utils::CameraIdAndSessionConfiguration>
&cameraIdsAndSessionConfigs,
- hardware::hidl_vec<hardware::camera::provider::V2_6::CameraIdAndStreamCombination>
+ hardware::hidl_vec<hardware::camera::provider::V2_7::CameraIdAndStreamCombination>
*halCameraIdsAndStreamCombinations,
bool *earlyExit);
};
diff --git a/services/camera/libcameraservice/device3/Camera3BufferManager.cpp b/services/camera/libcameraservice/device3/Camera3BufferManager.cpp
index d6bf83e..a556200 100644
--- a/services/camera/libcameraservice/device3/Camera3BufferManager.cpp
+++ b/services/camera/libcameraservice/device3/Camera3BufferManager.cpp
@@ -40,16 +40,17 @@
ATRACE_CALL();
int streamId = streamInfo.streamId;
- int streamSetId = streamInfo.streamSetId;
+ StreamSetKey streamSetKey = {streamInfo.streamSetId, streamInfo.isMultiRes};
- if (streamId == CAMERA3_STREAM_ID_INVALID || streamSetId == CAMERA3_STREAM_SET_ID_INVALID) {
+ if (streamId == CAMERA3_STREAM_ID_INVALID ||
+ streamSetKey.id == CAMERA3_STREAM_SET_ID_INVALID) {
ALOGE("%s: Stream id (%d) or stream set id (%d) is invalid",
- __FUNCTION__, streamId, streamSetId);
+ __FUNCTION__, streamId, streamSetKey.id);
return BAD_VALUE;
}
if (streamInfo.totalBufferCount > kMaxBufferCount || streamInfo.totalBufferCount == 0) {
ALOGE("%s: Stream id (%d) with stream set id (%d) total buffer count %zu is invalid",
- __FUNCTION__, streamId, streamSetId, streamInfo.totalBufferCount);
+ __FUNCTION__, streamId, streamSetKey.id, streamInfo.totalBufferCount);
return BAD_VALUE;
}
if (!streamInfo.isConfigured) {
@@ -75,7 +76,8 @@
for (size_t i = 0; i < mStreamSetMap.size(); i++) {
ssize_t streamIdx = mStreamSetMap[i].streamInfoMap.indexOfKey(streamId);
if (streamIdx != NAME_NOT_FOUND &&
- mStreamSetMap[i].streamInfoMap[streamIdx].streamSetId != streamInfo.streamSetId) {
+ mStreamSetMap[i].streamInfoMap[streamIdx].streamSetId != streamInfo.streamSetId &&
+ mStreamSetMap[i].streamInfoMap[streamIdx].isMultiRes != streamInfo.isMultiRes) {
ALOGE("%s: It is illegal to register the same stream id with different stream set",
__FUNCTION__);
return BAD_VALUE;
@@ -83,20 +85,20 @@
}
// Check if there is an existing stream set registered; if not, create one; otherwise, add this
// stream info to the existing stream set entry.
- ssize_t setIdx = mStreamSetMap.indexOfKey(streamSetId);
+ ssize_t setIdx = mStreamSetMap.indexOfKey(streamSetKey);
if (setIdx == NAME_NOT_FOUND) {
- ALOGV("%s: stream set %d is not registered to stream set map yet, create it.",
- __FUNCTION__, streamSetId);
+ ALOGV("%s: stream set %d(%d) is not registered to stream set map yet, create it.",
+ __FUNCTION__, streamSetKey.id, streamSetKey.isMultiRes);
// Create stream info map, then add to mStreamsetMap.
StreamSet newStreamSet;
- setIdx = mStreamSetMap.add(streamSetId, newStreamSet);
+ setIdx = mStreamSetMap.add(streamSetKey, newStreamSet);
}
// Update stream set map and water mark.
StreamSet& currentStreamSet = mStreamSetMap.editValueAt(setIdx);
ssize_t streamIdx = currentStreamSet.streamInfoMap.indexOfKey(streamId);
if (streamIdx != NAME_NOT_FOUND) {
- ALOGW("%s: stream %d was already registered with stream set %d",
- __FUNCTION__, streamId, streamSetId);
+ ALOGW("%s: stream %d was already registered with stream set %d(%d)",
+ __FUNCTION__, streamId, streamSetKey.id, streamSetKey.isMultiRes);
return OK;
}
currentStreamSet.streamInfoMap.add(streamId, streamInfo);
@@ -113,21 +115,22 @@
return OK;
}
-status_t Camera3BufferManager::unregisterStream(int streamId, int streamSetId) {
+status_t Camera3BufferManager::unregisterStream(int streamId, int streamSetId, bool isMultiRes) {
ATRACE_CALL();
Mutex::Autolock l(mLock);
- ALOGV("%s: unregister stream %d with stream set %d", __FUNCTION__,
- streamId, streamSetId);
+ ALOGV("%s: unregister stream %d with stream set %d(%d)", __FUNCTION__,
+ streamId, streamSetId, isMultiRes);
- if (!checkIfStreamRegisteredLocked(streamId, streamSetId)){
- ALOGE("%s: stream %d with set id %d wasn't properly registered to this buffer manager!",
- __FUNCTION__, streamId, streamSetId);
+ StreamSetKey streamSetKey = {streamSetId, isMultiRes};
+ if (!checkIfStreamRegisteredLocked(streamId, streamSetKey)){
+ ALOGE("%s: stream %d with set %d(%d) wasn't properly registered to this"
+ " buffer manager!", __FUNCTION__, streamId, streamSetId, isMultiRes);
return BAD_VALUE;
}
// De-list all the buffers associated with this stream first.
- StreamSet& currentSet = mStreamSetMap.editValueFor(streamSetId);
+ StreamSet& currentSet = mStreamSetMap.editValueFor(streamSetKey);
BufferCountMap& handOutBufferCounts = currentSet.handoutBufferCountMap;
BufferCountMap& attachedBufferCounts = currentSet.attachedBufferCountMap;
InfoMap& infoMap = currentSet.streamInfoMap;
@@ -150,26 +153,28 @@
// Remove this stream set if all its streams have been removed.
if (handOutBufferCounts.size() == 0 && infoMap.size() == 0) {
- mStreamSetMap.removeItem(streamSetId);
+ mStreamSetMap.removeItem(streamSetKey);
}
return OK;
}
-void Camera3BufferManager::notifyBufferRemoved(int streamId, int streamSetId) {
+void Camera3BufferManager::notifyBufferRemoved(int streamId, int streamSetId, bool isMultiRes) {
Mutex::Autolock l(mLock);
- StreamSet &streamSet = mStreamSetMap.editValueFor(streamSetId);
+ StreamSetKey streamSetKey = {streamSetId, isMultiRes};
+ StreamSet &streamSet = mStreamSetMap.editValueFor(streamSetKey);
size_t& attachedBufferCount =
streamSet.attachedBufferCountMap.editValueFor(streamId);
attachedBufferCount--;
}
status_t Camera3BufferManager::checkAndFreeBufferOnOtherStreamsLocked(
- int streamId, int streamSetId) {
+ int streamId, StreamSetKey streamSetKey) {
StreamId firstOtherStreamId = CAMERA3_STREAM_ID_INVALID;
- StreamSet &streamSet = mStreamSetMap.editValueFor(streamSetId);
+ StreamSet &streamSet = mStreamSetMap.editValueFor(streamSetKey);
if (streamSet.streamInfoMap.size() == 1) {
- ALOGV("StreamSet %d has no other stream available to free", streamSetId);
+ ALOGV("StreamSet %d(%d) has no other stream available to free",
+ streamSetKey.id, streamSetKey.isMultiRes);
return OK;
}
@@ -190,7 +195,8 @@
firstOtherStreamId = CAMERA3_STREAM_ID_INVALID;
}
if (firstOtherStreamId == CAMERA3_STREAM_ID_INVALID || !freeBufferIsAttached) {
- ALOGV("StreamSet %d has no buffer available to free", streamSetId);
+ ALOGV("StreamSet %d(%d) has no buffer available to free",
+ streamSetKey.id, streamSetKey.isMultiRes);
return OK;
}
@@ -237,20 +243,21 @@
}
status_t Camera3BufferManager::getBufferForStream(int streamId, int streamSetId,
- sp<GraphicBuffer>* gb, int* fenceFd, bool noFreeBufferAtConsumer) {
+ bool isMultiRes, sp<GraphicBuffer>* gb, int* fenceFd, bool noFreeBufferAtConsumer) {
ATRACE_CALL();
Mutex::Autolock l(mLock);
- ALOGV("%s: get buffer for stream %d with stream set %d", __FUNCTION__,
- streamId, streamSetId);
+ ALOGV("%s: get buffer for stream %d with stream set %d(%d)", __FUNCTION__,
+ streamId, streamSetId, isMultiRes);
- if (!checkIfStreamRegisteredLocked(streamId, streamSetId)) {
- ALOGE("%s: stream %d is not registered with stream set %d yet!!!",
- __FUNCTION__, streamId, streamSetId);
+ StreamSetKey streamSetKey = {streamSetId, isMultiRes};
+ if (!checkIfStreamRegisteredLocked(streamId, streamSetKey)) {
+ ALOGE("%s: stream %d is not registered with stream set %d(%d) yet!!!",
+ __FUNCTION__, streamId, streamSetId, isMultiRes);
return BAD_VALUE;
}
- StreamSet &streamSet = mStreamSetMap.editValueFor(streamSetId);
+ StreamSet &streamSet = mStreamSetMap.editValueFor(streamSetKey);
BufferCountMap& handOutBufferCounts = streamSet.handoutBufferCountMap;
size_t& bufferCount = handOutBufferCounts.editValueFor(streamId);
BufferCountMap& attachedBufferCounts = streamSet.attachedBufferCountMap;
@@ -272,7 +279,8 @@
bufferCount++;
return ALREADY_EXISTS;
}
- ALOGV("Stream %d set %d: Get buffer for stream: Allocate new", streamId, streamSetId);
+ ALOGV("Stream %d set %d(%d): Get buffer for stream: Allocate new",
+ streamId, streamSetId, isMultiRes);
if (mGrallocVersion < HARDWARE_DEVICE_API_VERSION(1,0)) {
const StreamInfo& info = streamSet.streamInfoMap.valueFor(streamId);
@@ -313,13 +321,13 @@
// in returnBufferForStream() if we want to free buffer more quickly.
// TODO: probably should find out all the inactive stream IDs, and free the firstly found
// buffers for them.
- res = checkAndFreeBufferOnOtherStreamsLocked(streamId, streamSetId);
+ res = checkAndFreeBufferOnOtherStreamsLocked(streamId, streamSetKey);
if (res != OK) {
return res;
}
// Since we just allocated one new buffer above, try free one more buffer from other streams
// to prevent total buffer count from growing
- res = checkAndFreeBufferOnOtherStreamsLocked(streamId, streamSetId);
+ res = checkAndFreeBufferOnOtherStreamsLocked(streamId, streamSetKey);
if (res != OK) {
return res;
}
@@ -332,7 +340,7 @@
}
status_t Camera3BufferManager::onBufferReleased(
- int streamId, int streamSetId, bool* shouldFreeBuffer) {
+ int streamId, int streamSetId, bool isMultiRes, bool* shouldFreeBuffer) {
ATRACE_CALL();
if (shouldFreeBuffer == nullptr) {
@@ -341,22 +349,24 @@
}
Mutex::Autolock l(mLock);
- ALOGV("Stream %d set %d: Buffer released", streamId, streamSetId);
+ ALOGV("Stream %d set %d(%d): Buffer released", streamId, streamSetId, isMultiRes);
*shouldFreeBuffer = false;
- if (!checkIfStreamRegisteredLocked(streamId, streamSetId)){
+ StreamSetKey streamSetKey = {streamSetId, isMultiRes};
+ if (!checkIfStreamRegisteredLocked(streamId, streamSetKey)){
ALOGV("%s: signaling buffer release for an already unregistered stream "
- "(stream %d with set id %d)", __FUNCTION__, streamId, streamSetId);
+ "(stream %d with set id %d(%d))", __FUNCTION__, streamId, streamSetId,
+ isMultiRes);
return OK;
}
if (mGrallocVersion < HARDWARE_DEVICE_API_VERSION(1,0)) {
- StreamSet& streamSet = mStreamSetMap.editValueFor(streamSetId);
+ StreamSet& streamSet = mStreamSetMap.editValueFor(streamSetKey);
BufferCountMap& handOutBufferCounts = streamSet.handoutBufferCountMap;
size_t& bufferCount = handOutBufferCounts.editValueFor(streamId);
bufferCount--;
- ALOGV("%s: Stream %d set %d: Buffer count now %zu", __FUNCTION__, streamId, streamSetId,
- bufferCount);
+ ALOGV("%s: Stream %d set %d(%d): Buffer count now %zu", __FUNCTION__, streamId,
+ streamSetId, isMultiRes, bufferCount);
size_t totalAllocatedBufferCount = 0;
size_t totalHandOutBufferCount = 0;
@@ -371,8 +381,9 @@
// BufferManager got more than enough buffers, so decrease watermark
// to trigger more buffers free operation.
streamSet.allocatedBufferWaterMark = newWaterMark;
- ALOGV("%s: Stream %d set %d: watermark--; now %zu",
- __FUNCTION__, streamId, streamSetId, streamSet.allocatedBufferWaterMark);
+ ALOGV("%s: Stream %d set %d(%d): watermark--; now %zu",
+ __FUNCTION__, streamId, streamSetId, isMultiRes,
+ streamSet.allocatedBufferWaterMark);
}
size_t attachedBufferCount = streamSet.attachedBufferCountMap.valueFor(streamId);
@@ -395,20 +406,22 @@
return OK;
}
-status_t Camera3BufferManager::onBuffersRemoved(int streamId, int streamSetId, size_t count) {
+status_t Camera3BufferManager::onBuffersRemoved(int streamId, int streamSetId,
+ bool isMultiRes, size_t count) {
ATRACE_CALL();
Mutex::Autolock l(mLock);
- ALOGV("Stream %d set %d: Buffer removed", streamId, streamSetId);
+ ALOGV("Stream %d set %d(%d): Buffer removed", streamId, streamSetId, isMultiRes);
- if (!checkIfStreamRegisteredLocked(streamId, streamSetId)){
+ StreamSetKey streamSetKey = {streamSetId, isMultiRes};
+ if (!checkIfStreamRegisteredLocked(streamId, streamSetKey)){
ALOGV("%s: signaling buffer removal for an already unregistered stream "
- "(stream %d with set id %d)", __FUNCTION__, streamId, streamSetId);
+ "(stream %d with set id %d(%d))", __FUNCTION__, streamId, streamSetId, isMultiRes);
return OK;
}
if (mGrallocVersion < HARDWARE_DEVICE_API_VERSION(1,0)) {
- StreamSet& streamSet = mStreamSetMap.editValueFor(streamSetId);
+ StreamSet& streamSet = mStreamSetMap.editValueFor(streamSetKey);
BufferCountMap& handOutBufferCounts = streamSet.handoutBufferCountMap;
size_t& totalHandoutCount = handOutBufferCounts.editValueFor(streamId);
BufferCountMap& attachedBufferCounts = streamSet.attachedBufferCountMap;
@@ -427,8 +440,9 @@
totalHandoutCount -= count;
totalAttachedCount -= count;
- ALOGV("%s: Stream %d set %d: Buffer count now %zu, attached buffer count now %zu",
- __FUNCTION__, streamId, streamSetId, totalHandoutCount, totalAttachedCount);
+ ALOGV("%s: Stream %d set %d(%d): Buffer count now %zu, attached buffer count now %zu",
+ __FUNCTION__, streamId, streamSetId, isMultiRes, totalHandoutCount,
+ totalAttachedCount);
} else {
// TODO: implement gralloc V1 support
return BAD_VALUE;
@@ -444,7 +458,8 @@
String8 lines;
lines.appendFormat(" Total stream sets: %zu\n", mStreamSetMap.size());
for (size_t i = 0; i < mStreamSetMap.size(); i++) {
- lines.appendFormat(" Stream set %d has below streams:\n", mStreamSetMap.keyAt(i));
+ lines.appendFormat(" Stream set %d(%d) has below streams:\n",
+ mStreamSetMap.keyAt(i).id, mStreamSetMap.keyAt(i).isMultiRes);
for (size_t j = 0; j < mStreamSetMap[i].streamInfoMap.size(); j++) {
lines.appendFormat(" Stream %d\n", mStreamSetMap[i].streamInfoMap[j].streamId);
}
@@ -470,11 +485,12 @@
write(fd, lines.string(), lines.size());
}
-bool Camera3BufferManager::checkIfStreamRegisteredLocked(int streamId, int streamSetId) const {
- ssize_t setIdx = mStreamSetMap.indexOfKey(streamSetId);
+bool Camera3BufferManager::checkIfStreamRegisteredLocked(int streamId,
+ StreamSetKey streamSetKey) const {
+ ssize_t setIdx = mStreamSetMap.indexOfKey(streamSetKey);
if (setIdx == NAME_NOT_FOUND) {
- ALOGV("%s: stream set %d is not registered to stream set map yet!",
- __FUNCTION__, streamSetId);
+ ALOGV("%s: stream set %d(%d) is not registered to stream set map yet!",
+ __FUNCTION__, streamSetKey.id, streamSetKey.isMultiRes);
return false;
}
@@ -486,9 +502,10 @@
size_t bufferWaterMark = mStreamSetMap[setIdx].maxAllowedBufferCount;
if (bufferWaterMark == 0 || bufferWaterMark > kMaxBufferCount) {
- ALOGW("%s: stream %d with stream set %d is not registered correctly to stream set map,"
+ ALOGW("%s: stream %d with stream set %d(%d) is not registered correctly to stream set map,"
" as the water mark (%zu) is wrong!",
- __FUNCTION__, streamId, streamSetId, bufferWaterMark);
+ __FUNCTION__, streamId, streamSetKey.id, streamSetKey.isMultiRes,
+ bufferWaterMark);
return false;
}
diff --git a/services/camera/libcameraservice/device3/Camera3BufferManager.h b/services/camera/libcameraservice/device3/Camera3BufferManager.h
index f0de1c1..64aaa230 100644
--- a/services/camera/libcameraservice/device3/Camera3BufferManager.h
+++ b/services/camera/libcameraservice/device3/Camera3BufferManager.h
@@ -99,7 +99,7 @@
* combination doesn't match what was registered, or this stream wasn't registered
* to this buffer manager before.
*/
- status_t unregisterStream(int streamId, int streamSetId);
+ status_t unregisterStream(int streamId, int streamSetId, bool isMultiRes);
/**
* This method obtains a buffer for a stream from this buffer manager.
@@ -127,8 +127,8 @@
* NO_MEMORY: Unable to allocate a buffer for this stream at this time.
*/
status_t getBufferForStream(
- int streamId, int streamSetId, sp<GraphicBuffer>* gb, int* fenceFd,
- bool noFreeBufferAtConsumer = false);
+ int streamId, int streamSetId, bool isMultiRes, sp<GraphicBuffer>* gb,
+ int* fenceFd, bool noFreeBufferAtConsumer = false);
/**
* This method notifies the manager that a buffer has been released by the consumer.
@@ -153,7 +153,8 @@
* combination doesn't match what was registered, or this stream wasn't registered
* to this buffer manager before, or shouldFreeBuffer is null/
*/
- status_t onBufferReleased(int streamId, int streamSetId, /*out*/bool* shouldFreeBuffer);
+ status_t onBufferReleased(int streamId, int streamSetId, bool isMultiRes,
+ /*out*/bool* shouldFreeBuffer);
/**
* This method notifies the manager that certain buffers has been removed from the
@@ -171,13 +172,13 @@
* to this buffer manager before, or the removed buffer count is larger than
* current total handoutCount or attachedCount.
*/
- status_t onBuffersRemoved(int streamId, int streamSetId, size_t count);
+ status_t onBuffersRemoved(int streamId, int streamSetId, bool isMultiRes, size_t count);
/**
* This method notifiers the manager that a buffer is freed from the buffer queue, usually
* because onBufferReleased signals the caller to free a buffer via the shouldFreeBuffer flag.
*/
- void notifyBufferRemoved(int streamId, int streamSetId);
+ void notifyBufferRemoved(int streamId, int streamSetId, bool isMultiRes);
/**
* Dump the buffer manager statistics.
@@ -292,8 +293,20 @@
/**
* Stream set map managed by this buffer manager.
*/
- typedef int StreamSetId;
- KeyedVector<StreamSetId, StreamSet> mStreamSetMap;
+ struct StreamSetKey {
+ // The stream set ID
+ int id;
+ // Whether this stream set is for multi-resolution output streams. It's
+ // valid for 2 stream sets to have the same stream set ID if: one is for
+ // multi-resolution output stream, and the other one is not.
+ bool isMultiRes;
+
+ inline bool operator<(const StreamSetKey& other) const {
+ return (isMultiRes < other.isMultiRes) ||
+ ((isMultiRes == other.isMultiRes) && (id < other.id));
+ }
+ };
+ KeyedVector<StreamSetKey, StreamSet> mStreamSetMap;
KeyedVector<StreamId, wp<Camera3OutputStream>> mStreamMap;
// TODO: There is no easy way to query the Gralloc version in this code yet, we have different
@@ -304,13 +317,13 @@
* Check if this stream was successfully registered already. This method needs to be called with
* mLock held.
*/
- bool checkIfStreamRegisteredLocked(int streamId, int streamSetId) const;
+ bool checkIfStreamRegisteredLocked(int streamId, StreamSetKey streamSetKey) const;
/**
* Check if other streams in the stream set has extra buffer available to be freed, and
* free one if so.
*/
- status_t checkAndFreeBufferOnOtherStreamsLocked(int streamId, int streamSetId);
+ status_t checkAndFreeBufferOnOtherStreamsLocked(int streamId, StreamSetKey streamSetKey);
};
} // namespace camera3
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 73a133f..35a06d8 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -313,6 +313,7 @@
mFakeStreamId = NO_STREAM;
mNeedConfig = true;
mPauseStateNotify = false;
+ mIsInputStreamMultiResolution = false;
// Measure the clock domain offset between camera and video/hw_composer
camera_metadata_entry timestampSource =
@@ -481,7 +482,7 @@
return gotLock;
}
-Camera3Device::Size Camera3Device::getMaxJpegResolution() const {
+camera3::Size Camera3Device::getMaxJpegResolution() const {
int32_t maxJpegWidth = 0, maxJpegHeight = 0;
const int STREAM_CONFIGURATION_SIZE = 4;
const int STREAM_FORMAT_OFFSET = 0;
@@ -492,7 +493,7 @@
mDeviceInfo.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
if (availableStreamConfigs.count == 0 ||
availableStreamConfigs.count % STREAM_CONFIGURATION_SIZE != 0) {
- return Size(0, 0);
+ return camera3::Size(0, 0);
}
// Get max jpeg size (area-wise).
@@ -509,7 +510,7 @@
}
}
- return Size(maxJpegWidth, maxJpegHeight);
+ return camera3::Size(maxJpegWidth, maxJpegHeight);
}
nsecs_t Camera3Device::getMonoToBoottimeOffset() {
@@ -603,7 +604,7 @@
ssize_t Camera3Device::getJpegBufferSize(uint32_t width, uint32_t height) const {
// Get max jpeg size (area-wise).
- Size maxJpegResolution = getMaxJpegResolution();
+ camera3::Size maxJpegResolution = getMaxJpegResolution();
if (maxJpegResolution.width == 0) {
ALOGE("%s: Camera %s: Can't find valid available jpeg sizes in static metadata!",
__FUNCTION__, mId.string());
@@ -1252,7 +1253,7 @@
}
status_t Camera3Device::createInputStream(
- uint32_t width, uint32_t height, int format, int *id) {
+ uint32_t width, uint32_t height, int format, bool isMultiResolution, int *id) {
ATRACE_CALL();
Mutex::Autolock il(mInterfaceLock);
nsecs_t maxExpectedDuration = getExpectedInFlightDuration();
@@ -1299,6 +1300,7 @@
newStream->setStatusTracker(mStatusTracker);
mInputStream = newStream;
+ mIsInputStreamMultiResolution = isMultiResolution;
*id = mNextStreamId++;
@@ -1323,7 +1325,8 @@
uint32_t width, uint32_t height, int format,
android_dataspace dataSpace, camera_stream_rotation_t rotation, int *id,
const String8& physicalCameraId,
- std::vector<int> *surfaceIds, int streamSetId, bool isShared, uint64_t consumerUsage) {
+ std::vector<int> *surfaceIds, int streamSetId, bool isShared,
+ bool isMultiResolution, uint64_t consumerUsage) {
ATRACE_CALL();
if (consumer == nullptr) {
@@ -1336,23 +1339,24 @@
return createStream(consumers, /*hasDeferredConsumer*/ false, width, height,
format, dataSpace, rotation, id, physicalCameraId, surfaceIds, streamSetId,
- isShared, consumerUsage);
+ isShared, isMultiResolution, consumerUsage);
}
status_t Camera3Device::createStream(const std::vector<sp<Surface>>& consumers,
bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
android_dataspace dataSpace, camera_stream_rotation_t rotation, int *id,
const String8& physicalCameraId,
- std::vector<int> *surfaceIds, int streamSetId, bool isShared, uint64_t consumerUsage) {
+ std::vector<int> *surfaceIds, int streamSetId, bool isShared, bool isMultiResolution,
+ uint64_t consumerUsage) {
ATRACE_CALL();
Mutex::Autolock il(mInterfaceLock);
nsecs_t maxExpectedDuration = getExpectedInFlightDuration();
Mutex::Autolock l(mLock);
ALOGV("Camera %s: Creating new stream %d: %d x %d, format %d, dataspace %d rotation %d"
- " consumer usage %" PRIu64 ", isShared %d, physicalCameraId %s", mId.string(),
- mNextStreamId, width, height, format, dataSpace, rotation, consumerUsage, isShared,
- physicalCameraId.string());
+ " consumer usage %" PRIu64 ", isShared %d, physicalCameraId %s, isMultiResolution %d",
+ mId.string(), mNextStreamId, width, height, format, dataSpace, rotation,
+ consumerUsage, isShared, physicalCameraId.string(), isMultiResolution);
status_t res;
bool wasActive = false;
@@ -1414,7 +1418,7 @@
}
newStream = new Camera3OutputStream(mNextStreamId, consumers[0],
width, height, blobBufferSize, format, dataSpace, rotation,
- mTimestampOffset, physicalCameraId, streamSetId);
+ mTimestampOffset, physicalCameraId, streamSetId, isMultiResolution);
} else if (format == HAL_PIXEL_FORMAT_RAW_OPAQUE) {
ssize_t rawOpaqueBufferSize = getRawOpaqueBufferSize(width, height);
if (rawOpaqueBufferSize <= 0) {
@@ -1423,20 +1427,19 @@
}
newStream = new Camera3OutputStream(mNextStreamId, consumers[0],
width, height, rawOpaqueBufferSize, format, dataSpace, rotation,
- mTimestampOffset, physicalCameraId, streamSetId);
+ mTimestampOffset, physicalCameraId, streamSetId, isMultiResolution);
} else if (isShared) {
newStream = new Camera3SharedOutputStream(mNextStreamId, consumers,
width, height, format, consumerUsage, dataSpace, rotation,
- mTimestampOffset, physicalCameraId, streamSetId,
- mUseHalBufManager);
+ mTimestampOffset, physicalCameraId, streamSetId, mUseHalBufManager);
} else if (consumers.size() == 0 && hasDeferredConsumer) {
newStream = new Camera3OutputStream(mNextStreamId,
width, height, format, consumerUsage, dataSpace, rotation,
- mTimestampOffset, physicalCameraId, streamSetId);
+ mTimestampOffset, physicalCameraId, streamSetId, isMultiResolution);
} else {
newStream = new Camera3OutputStream(mNextStreamId, consumers[0],
width, height, format, dataSpace, rotation,
- mTimestampOffset, physicalCameraId, streamSetId);
+ mTimestampOffset, physicalCameraId, streamSetId, isMultiResolution);
}
size_t consumerCount = consumers.size();
@@ -2549,8 +2552,9 @@
if (mInputStream != NULL && notifyRequestThread) {
while (true) {
camera_stream_buffer_t inputBuffer;
+ camera3::Size inputBufferSize;
status_t res = mInputStream->getInputBuffer(&inputBuffer,
- /*respectHalLimit*/ false);
+ &inputBufferSize, /*respectHalLimit*/ false);
if (res != OK) {
// Exhausted acquiring all input buffers.
break;
@@ -2587,6 +2591,7 @@
camera_stream_configuration config;
config.operation_mode = mOperatingMode;
config.num_streams = (mInputStream != NULL) + mOutputStreams.size();
+ config.input_is_multi_resolution = false;
Vector<camera3::camera_stream_t*> streams;
streams.setCapacity(config.num_streams);
@@ -2602,6 +2607,8 @@
return INVALID_OPERATION;
}
streams.add(inputStream);
+
+ config.input_is_multi_resolution = mIsInputStreamMultiResolution;
}
for (size_t i = 0; i < mOutputStreams.size(); i++) {
@@ -2999,6 +3006,10 @@
mSupportOfflineProcessing(supportOfflineProcessing) {
// Check with hardware service manager if we can downcast these interfaces
// Somewhat expensive, so cache the results at startup
+ auto castResult_3_7 = device::V3_7::ICameraDeviceSession::castFrom(mHidlSession);
+ if (castResult_3_7.isOk()) {
+ mHidlSession_3_7 = castResult_3_7;
+ }
auto castResult_3_6 = device::V3_6::ICameraDeviceSession::castFrom(mHidlSession);
if (castResult_3_6.isOk()) {
mHidlSession_3_6 = castResult_3_6;
@@ -3032,6 +3043,7 @@
}
void Camera3Device::HalInterface::clear() {
+ mHidlSession_3_7.clear();
mHidlSession_3_6.clear();
mHidlSession_3_5.clear();
mHidlSession_3_4.clear();
@@ -3158,15 +3170,23 @@
if (!valid()) return INVALID_OPERATION;
status_t res = OK;
+ if (config->input_is_multi_resolution && mHidlSession_3_7 == nullptr) {
+ ALOGE("%s: Camera device doesn't support multi-resolution input stream", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
// Convert stream config to HIDL
std::set<int> activeStreams;
device::V3_2::StreamConfiguration requestedConfiguration3_2;
device::V3_4::StreamConfiguration requestedConfiguration3_4;
+ device::V3_7::StreamConfiguration requestedConfiguration3_7;
requestedConfiguration3_2.streams.resize(config->num_streams);
requestedConfiguration3_4.streams.resize(config->num_streams);
+ requestedConfiguration3_7.streams.resize(config->num_streams);
for (size_t i = 0; i < config->num_streams; i++) {
device::V3_2::Stream &dst3_2 = requestedConfiguration3_2.streams[i];
device::V3_4::Stream &dst3_4 = requestedConfiguration3_4.streams[i];
+ device::V3_7::Stream &dst3_7 = requestedConfiguration3_7.streams[i];
camera3::camera_stream_t *src = config->streams[i];
Camera3Stream* cam3stream = Camera3Stream::cast(src);
@@ -3207,6 +3227,8 @@
if (src->physical_camera_id != nullptr) {
dst3_4.physicalCameraId = src->physical_camera_id;
}
+ dst3_7.v3_4 = dst3_4;
+ dst3_7.groupId = cam3stream->getHalStreamGroupId();
activeStreams.insert(streamId);
// Create Buffer ID map if necessary
@@ -3227,6 +3249,10 @@
requestedConfiguration3_4.sessionParams.setToExternal(
reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(sessionParams)),
get_camera_metadata_size(sessionParams));
+ requestedConfiguration3_7.operationMode = operationMode;
+ requestedConfiguration3_7.sessionParams.setToExternal(
+ reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(sessionParams)),
+ get_camera_metadata_size(sessionParams));
// Invoke configureStreams
device::V3_3::HalStreamConfiguration finalConfiguration;
@@ -3273,7 +3299,17 @@
};
// See which version of HAL we have
- if (mHidlSession_3_6 != nullptr) {
+ if (mHidlSession_3_7 != nullptr) {
+ ALOGV("%s: v3.7 device found", __FUNCTION__);
+ requestedConfiguration3_7.streamConfigCounter = mNextStreamConfigCounter++;
+ requestedConfiguration3_7.multiResolutionInputImage = config->input_is_multi_resolution;
+ auto err = mHidlSession_3_7->configureStreams_3_7(
+ requestedConfiguration3_7, configStream36Cb);
+ res = postprocConfigStream36(err);
+ if (res != OK) {
+ return res;
+ }
+ } else if (mHidlSession_3_6 != nullptr) {
ALOGV("%s: v3.6 device found", __FUNCTION__);
device::V3_5::StreamConfiguration requestedConfiguration3_5;
requestedConfiguration3_5.v3_4 = requestedConfiguration3_4;
@@ -3531,6 +3567,11 @@
if (!valid()) return INVALID_OPERATION;
sp<device::V3_4::ICameraDeviceSession> hidlSession_3_4;
+ sp<device::V3_7::ICameraDeviceSession> hidlSession_3_7;
+ auto castResult_3_7 = device::V3_7::ICameraDeviceSession::castFrom(mHidlSession);
+ if (castResult_3_7.isOk()) {
+ hidlSession_3_7 = castResult_3_7;
+ }
auto castResult_3_4 = device::V3_4::ICameraDeviceSession::castFrom(mHidlSession);
if (castResult_3_4.isOk()) {
hidlSession_3_4 = castResult_3_4;
@@ -3538,8 +3579,11 @@
hardware::hidl_vec<device::V3_2::CaptureRequest> captureRequests;
hardware::hidl_vec<device::V3_4::CaptureRequest> captureRequests_3_4;
+ hardware::hidl_vec<device::V3_7::CaptureRequest> captureRequests_3_7;
size_t batchSize = requests.size();
- if (hidlSession_3_4 != nullptr) {
+ if (hidlSession_3_7 != nullptr) {
+ captureRequests_3_7.resize(batchSize);
+ } else if (hidlSession_3_4 != nullptr) {
captureRequests_3_4.resize(batchSize);
} else {
captureRequests.resize(batchSize);
@@ -3549,7 +3593,10 @@
status_t res = OK;
for (size_t i = 0; i < batchSize; i++) {
- if (hidlSession_3_4 != nullptr) {
+ if (hidlSession_3_7 != nullptr) {
+ res = wrapAsHidlRequest(requests[i], /*out*/&captureRequests_3_7[i].v3_4.v3_2,
+ /*out*/&handlesCreated, /*out*/&inflightBuffers);
+ } else if (hidlSession_3_4 != nullptr) {
res = wrapAsHidlRequest(requests[i], /*out*/&captureRequests_3_4[i].v3_2,
/*out*/&handlesCreated, /*out*/&inflightBuffers);
} else {
@@ -3582,7 +3629,9 @@
for (size_t i = 0; i < batchSize; i++) {
camera_capture_request_t* request = requests[i];
device::V3_2::CaptureRequest* captureRequest;
- if (hidlSession_3_4 != nullptr) {
+ if (hidlSession_3_7 != nullptr) {
+ captureRequest = &captureRequests_3_7[i].v3_4.v3_2;
+ } else if (hidlSession_3_4 != nullptr) {
captureRequest = &captureRequests_3_4[i].v3_2;
} else {
captureRequest = &captureRequests[i];
@@ -3609,33 +3658,42 @@
captureRequest->fmqSettingsSize = 0u;
}
- if (hidlSession_3_4 != nullptr) {
- captureRequests_3_4[i].physicalCameraSettings.resize(request->num_physcam_settings);
+ // hidl session 3.7 specific handling.
+ if (hidlSession_3_7 != nullptr) {
+ captureRequests_3_7[i].inputWidth = request->input_width;
+ captureRequests_3_7[i].inputHeight = request->input_height;
+ }
+
+ // hidl session 3.7 and 3.4 specific handling.
+ if (hidlSession_3_7 != nullptr || hidlSession_3_4 != nullptr) {
+ hardware::hidl_vec<device::V3_4::PhysicalCameraSetting>& physicalCameraSettings =
+ (hidlSession_3_7 != nullptr) ?
+ captureRequests_3_7[i].v3_4.physicalCameraSettings :
+ captureRequests_3_4[i].physicalCameraSettings;
+ physicalCameraSettings.resize(request->num_physcam_settings);
for (size_t j = 0; j < request->num_physcam_settings; j++) {
if (request->physcam_settings != nullptr) {
size_t settingsSize = get_camera_metadata_size(request->physcam_settings[j]);
if (mRequestMetadataQueue != nullptr && mRequestMetadataQueue->write(
reinterpret_cast<const uint8_t*>(request->physcam_settings[j]),
settingsSize)) {
- captureRequests_3_4[i].physicalCameraSettings[j].settings.resize(0);
- captureRequests_3_4[i].physicalCameraSettings[j].fmqSettingsSize =
- settingsSize;
+ physicalCameraSettings[j].settings.resize(0);
+ physicalCameraSettings[j].fmqSettingsSize = settingsSize;
} else {
if (mRequestMetadataQueue != nullptr) {
ALOGW("%s: couldn't utilize fmq, fallback to hwbinder", __FUNCTION__);
}
- captureRequests_3_4[i].physicalCameraSettings[j].settings.setToExternal(
+ physicalCameraSettings[j].settings.setToExternal(
reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(
request->physcam_settings[j])),
get_camera_metadata_size(request->physcam_settings[j]));
- captureRequests_3_4[i].physicalCameraSettings[j].fmqSettingsSize = 0u;
+ physicalCameraSettings[j].fmqSettingsSize = 0u;
}
} else {
- captureRequests_3_4[i].physicalCameraSettings[j].fmqSettingsSize = 0u;
- captureRequests_3_4[i].physicalCameraSettings[j].settings.resize(0);
+ physicalCameraSettings[j].fmqSettingsSize = 0u;
+ physicalCameraSettings[j].settings.resize(0);
}
- captureRequests_3_4[i].physicalCameraSettings[j].physicalCameraId =
- request->physcam_id[j];
+ physicalCameraSettings[j].physicalCameraId = request->physcam_id[j];
}
}
}
@@ -3646,7 +3704,10 @@
status = s;
*numRequestProcessed = n;
};
- if (hidlSession_3_4 != nullptr) {
+ if (hidlSession_3_7 != nullptr) {
+ err = hidlSession_3_7->processCaptureRequest_3_7(captureRequests_3_7, cachesToRemove,
+ resultCallback);
+ } else if (hidlSession_3_4 != nullptr) {
err = hidlSession_3_4->processCaptureRequest_3_4(captureRequests_3_4, cachesToRemove,
resultCallback);
} else {
@@ -4055,8 +4116,9 @@
// Abort the input buffers for reprocess requests.
if ((*it)->mInputStream != NULL) {
camera_stream_buffer_t inputBuffer;
+ camera3::Size inputBufferSize;
status_t res = (*it)->mInputStream->getInputBuffer(&inputBuffer,
- /*respectHalLimit*/ false);
+ &inputBufferSize, /*respectHalLimit*/ false);
if (res != OK) {
ALOGW("%s: %d: couldn't get input buffer while clearing the request "
"list: %s (%d)", __FUNCTION__, __LINE__, strerror(-res), res);
@@ -4262,33 +4324,34 @@
void Camera3Device::RequestThread::updateNextRequest(NextRequest& nextRequest) {
// Update the latest request sent to HAL
- if (nextRequest.halRequest.settings != NULL) { // Don't update if they were unchanged
+ camera_capture_request_t& halRequest = nextRequest.halRequest;
+ if (halRequest.settings != NULL) { // Don't update if they were unchanged
Mutex::Autolock al(mLatestRequestMutex);
- camera_metadata_t* cloned = clone_camera_metadata(nextRequest.halRequest.settings);
+ camera_metadata_t* cloned = clone_camera_metadata(halRequest.settings);
mLatestRequest.acquire(cloned);
mLatestPhysicalRequest.clear();
- for (uint32_t i = 0; i < nextRequest.halRequest.num_physcam_settings; i++) {
- cloned = clone_camera_metadata(nextRequest.halRequest.physcam_settings[i]);
- mLatestPhysicalRequest.emplace(nextRequest.halRequest.physcam_id[i],
+ for (uint32_t i = 0; i < halRequest.num_physcam_settings; i++) {
+ cloned = clone_camera_metadata(halRequest.physcam_settings[i]);
+ mLatestPhysicalRequest.emplace(halRequest.physcam_id[i],
CameraMetadata(cloned));
}
sp<Camera3Device> parent = mParent.promote();
if (parent != NULL) {
parent->monitorMetadata(TagMonitor::REQUEST,
- nextRequest.halRequest.frame_number,
+ halRequest.frame_number,
0, mLatestRequest, mLatestPhysicalRequest);
}
}
- if (nextRequest.halRequest.settings != NULL) {
+ if (halRequest.settings != NULL) {
nextRequest.captureRequest->mSettingsList.begin()->metadata.unlock(
- nextRequest.halRequest.settings);
+ halRequest.settings);
}
- cleanupPhysicalSettings(nextRequest.captureRequest, &nextRequest.halRequest);
+ cleanupPhysicalSettings(nextRequest.captureRequest, &halRequest);
}
bool Camera3Device::RequestThread::updateSessionParameters(const CameraMetadata& settings) {
@@ -4651,6 +4714,9 @@
// Fill in buffers
if (captureRequest->mInputStream != NULL) {
halRequest->input_buffer = &captureRequest->mInputBuffer;
+
+ halRequest->input_width = captureRequest->mInputBufferSize.width;
+ halRequest->input_height = captureRequest->mInputBufferSize.height;
totalNumBuffers += 1;
} else {
halRequest->input_buffer = NULL;
@@ -4754,13 +4820,7 @@
}
String8 physicalCameraId = outputStream->getPhysicalCameraId();
-
if (!physicalCameraId.isEmpty()) {
- // Physical stream isn't supported for input request.
- if (halRequest->input_buffer) {
- CLOGE("Physical stream is not supported for input request");
- return INVALID_OPERATION;
- }
requestedPhysicalCameras.insert(physicalCameraId);
}
halRequest->num_output_buffers++;
@@ -5237,7 +5297,8 @@
// Since RequestThread::clear() removes buffers from the input stream,
// get the right buffer here before unlocking mRequestLock
if (nextRequest->mInputStream != NULL) {
- res = nextRequest->mInputStream->getInputBuffer(&nextRequest->mInputBuffer);
+ res = nextRequest->mInputStream->getInputBuffer(&nextRequest->mInputBuffer,
+ &nextRequest->mInputBufferSize);
if (res != OK) {
// Can't get input buffer from gralloc queue - this could be due to
// disconnected queue or other producer misbehavior, so not a fatal
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 09fa30a..018dbe5 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -35,6 +35,7 @@
#include <android/hardware/camera/device/3.4/ICameraDeviceSession.h>
#include <android/hardware/camera/device/3.5/ICameraDeviceSession.h>
#include <android/hardware/camera/device/3.6/ICameraDeviceSession.h>
+#include <android/hardware/camera/device/3.7/ICameraDeviceSession.h>
#include <android/hardware/camera/device/3.2/ICameraDeviceCallback.h>
#include <android/hardware/camera/device/3.4/ICameraDeviceCallback.h>
#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
@@ -52,6 +53,7 @@
#include "device3/InFlightRequest.h"
#include "device3/Camera3OutputInterface.h"
#include "device3/Camera3OfflineSession.h"
+#include "device3/Camera3StreamInterface.h"
#include "utils/TagMonitor.h"
#include "utils/LatencyHistogram.h"
#include <camera_metadata_hidden.h>
@@ -71,7 +73,6 @@
class Camera3Stream;
class Camera3ZslStream;
-class Camera3OutputStreamInterface;
class Camera3StreamInterface;
} // namespace camera3
@@ -133,17 +134,19 @@
const String8& physicalCameraId,
std::vector<int> *surfaceIds = nullptr,
int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID,
- bool isShared = false, uint64_t consumerUsage = 0) override;
+ bool isShared = false, bool isMultiResolution = false,
+ uint64_t consumerUsage = 0) override;
status_t createStream(const std::vector<sp<Surface>>& consumers,
bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
android_dataspace dataSpace, camera_stream_rotation_t rotation, int *id,
const String8& physicalCameraId,
std::vector<int> *surfaceIds = nullptr,
int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID,
- bool isShared = false, uint64_t consumerUsage = 0) override;
+ bool isShared = false, bool isMultiResolution = false,
+ uint64_t consumerUsage = 0) override;
status_t createInputStream(
- uint32_t width, uint32_t height, int format,
+ uint32_t width, uint32_t height, int format, bool isMultiResolution,
int *id) override;
status_t getStreamInfo(int id, StreamInfo *streamInfo) override;
@@ -418,6 +421,8 @@
sp<hardware::camera::device::V3_5::ICameraDeviceSession> mHidlSession_3_5;
// Valid if ICameraDeviceSession is @3.6 or newer
sp<hardware::camera::device::V3_6::ICameraDeviceSession> mHidlSession_3_6;
+ // Valid if ICameraDeviceSession is @3.7 or newer
+ sp<hardware::camera::device::V3_7::ICameraDeviceSession> mHidlSession_3_7;
std::shared_ptr<RequestMetadataQueue> mRequestMetadataQueue;
@@ -490,6 +495,7 @@
camera3::StreamSet mOutputStreams;
sp<camera3::Camera3Stream> mInputStream;
+ bool mIsInputStreamMultiResolution;
SessionStatsBuilder mSessionStatsBuilder;
int mNextStreamId;
@@ -523,6 +529,7 @@
PhysicalCameraSettingsList mSettingsList;
sp<camera3::Camera3Stream> mInputStream;
camera_stream_buffer_t mInputBuffer;
+ camera3::Size mInputBufferSize;
Vector<sp<camera3::Camera3OutputStreamInterface> >
mOutputStreams;
SurfaceMap mOutputSurfaces;
@@ -748,7 +755,7 @@
* Helper function to get the largest Jpeg resolution (in area)
* Return Size(0, 0) if static metatdata is invalid
*/
- Size getMaxJpegResolution() const;
+ camera3::Size getMaxJpegResolution() const;
/**
* Helper function to get the offset between MONOTONIC and BOOTTIME
diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
index f6acda8..a837900 100644
--- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
@@ -32,10 +32,10 @@
Camera3IOStreamBase::Camera3IOStreamBase(int id, camera_stream_type_t type,
uint32_t width, uint32_t height, size_t maxSize, int format,
android_dataspace dataSpace, camera_stream_rotation_t rotation,
- const String8& physicalCameraId, int setId) :
+ const String8& physicalCameraId, int setId, bool isMultiResolution) :
Camera3Stream(id, type,
width, height, maxSize, format, dataSpace, rotation,
- physicalCameraId, setId),
+ physicalCameraId, setId, isMultiResolution),
mTotalBufferCount(0),
mHandoutTotalBufferCount(0),
mHandoutOutputBufferCount(0),
diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
index 719fa14..2e744ee 100644
--- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
@@ -36,7 +36,7 @@
uint32_t width, uint32_t height, size_t maxSize, int format,
android_dataspace dataSpace, camera_stream_rotation_t rotation,
const String8& physicalCameraId,
- int setId = CAMERA3_STREAM_SET_ID_INVALID);
+ int setId = CAMERA3_STREAM_SET_ID_INVALID, bool isMultiResolution = false);
public:
diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.cpp b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
index ad70a3a..b00a963 100644
--- a/services/camera/libcameraservice/device3/Camera3InputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
@@ -46,10 +46,14 @@
}
status_t Camera3InputStream::getInputBufferLocked(
- camera_stream_buffer *buffer) {
+ camera_stream_buffer *buffer, Size *size) {
ATRACE_CALL();
status_t res;
+ if (size == nullptr) {
+ ALOGE("%s: size must not be null", __FUNCTION__);
+ return BAD_VALUE;
+ }
// FIXME: will not work in (re-)registration
if (mState == STATE_IN_CONFIG || mState == STATE_IN_RECONFIG) {
ALOGE("%s: Stream %d: Buffer registration for input streams"
@@ -77,10 +81,12 @@
return res;
}
+ size->width = bufferItem.mGraphicBuffer->getWidth();
+ size->height = bufferItem.mGraphicBuffer->getHeight();
+
anb = bufferItem.mGraphicBuffer->getNativeBuffer();
assert(anb != NULL);
fenceFd = bufferItem.mFence->dup();
-
/**
* FenceFD now owned by HAL except in case of error,
* in which case we reassign it to acquire_fence
diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.h b/services/camera/libcameraservice/device3/Camera3InputStream.h
index 03afa17..46221d1 100644
--- a/services/camera/libcameraservice/device3/Camera3InputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3InputStream.h
@@ -70,7 +70,7 @@
* Camera3Stream interface
*/
- virtual status_t getInputBufferLocked(camera_stream_buffer *buffer);
+ virtual status_t getInputBufferLocked(camera_stream_buffer *buffer, Size *size);
virtual status_t returnInputBufferLocked(
const camera_stream_buffer &buffer);
virtual status_t getInputBufferProducerLocked(
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index c835f51..3ec3b6b 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -44,10 +44,10 @@
uint32_t width, uint32_t height, int format,
android_dataspace dataSpace, camera_stream_rotation_t rotation,
nsecs_t timestampOffset, const String8& physicalCameraId,
- int setId) :
+ int setId, bool isMultiResolution) :
Camera3IOStreamBase(id, CAMERA_STREAM_OUTPUT, width, height,
/*maxSize*/0, format, dataSpace, rotation,
- physicalCameraId, setId),
+ physicalCameraId, setId, isMultiResolution),
mConsumer(consumer),
mTransform(0),
mTraceFirstBuffer(true),
@@ -70,9 +70,11 @@
sp<Surface> consumer,
uint32_t width, uint32_t height, size_t maxSize, int format,
android_dataspace dataSpace, camera_stream_rotation_t rotation,
- nsecs_t timestampOffset, const String8& physicalCameraId, int setId) :
+ nsecs_t timestampOffset, const String8& physicalCameraId, int setId,
+ bool isMultiResolution) :
Camera3IOStreamBase(id, CAMERA_STREAM_OUTPUT, width, height, maxSize,
- format, dataSpace, rotation, physicalCameraId, setId),
+ format, dataSpace, rotation, physicalCameraId, setId,
+ isMultiResolution),
mConsumer(consumer),
mTransform(0),
mTraceFirstBuffer(true),
@@ -102,10 +104,10 @@
uint32_t width, uint32_t height, int format,
uint64_t consumerUsage, android_dataspace dataSpace,
camera_stream_rotation_t rotation, nsecs_t timestampOffset,
- const String8& physicalCameraId, int setId) :
+ const String8& physicalCameraId, int setId, bool isMultiResolution) :
Camera3IOStreamBase(id, CAMERA_STREAM_OUTPUT, width, height,
/*maxSize*/0, format, dataSpace, rotation,
- physicalCameraId, setId),
+ physicalCameraId, setId, isMultiResolution),
mConsumer(nullptr),
mTransform(0),
mTraceFirstBuffer(true),
@@ -141,11 +143,11 @@
camera_stream_rotation_t rotation,
const String8& physicalCameraId,
uint64_t consumerUsage, nsecs_t timestampOffset,
- int setId) :
+ int setId, bool isMultiResolution) :
Camera3IOStreamBase(id, type, width, height,
/*maxSize*/0,
format, dataSpace, rotation,
- physicalCameraId, setId),
+ physicalCameraId, setId, isMultiResolution),
mTransform(0),
mTraceFirstBuffer(true),
mUseMonoTimestamp(false),
@@ -570,10 +572,12 @@
!(isConsumedByHWComposer() || isConsumedByHWTexture())) {
uint64_t consumerUsage = 0;
getEndpointUsage(&consumerUsage);
+ uint32_t width = (mMaxSize == 0) ? getWidth() : mMaxSize;
+ uint32_t height = (mMaxSize == 0) ? getHeight() : 1;
StreamInfo streamInfo(
- getId(), getStreamSetId(), getWidth(), getHeight(), getFormat(), getDataSpace(),
+ getId(), getStreamSetId(), width, height, getFormat(), getDataSpace(),
mUsage | consumerUsage, mTotalBufferCount,
- /*isConfigured*/true);
+ /*isConfigured*/true, isMultiResolution());
wp<Camera3OutputStream> weakThis(this);
res = mBufferManager->registerStream(weakThis,
streamInfo);
@@ -604,7 +608,8 @@
if (mUseBufferManager) {
sp<GraphicBuffer> gb;
- res = mBufferManager->getBufferForStream(getId(), getStreamSetId(), &gb, fenceFd);
+ res = mBufferManager->getBufferForStream(getId(), getStreamSetId(),
+ isMultiResolution(), &gb, fenceFd);
if (res == OK) {
// Attach this buffer to the bufferQueue: the buffer will be in dequeue state after a
// successful return.
@@ -693,7 +698,8 @@
sp<GraphicBuffer> gb;
res = mBufferManager->getBufferForStream(
- getId(), getStreamSetId(), &gb, fenceFd, /*noFreeBuffer*/true);
+ getId(), getStreamSetId(), isMultiResolution(),
+ &gb, fenceFd, /*noFreeBuffer*/true);
if (res == OK) {
// Attach this buffer to the bufferQueue: the buffer will be in dequeue state after
@@ -740,7 +746,8 @@
onBuffersRemovedLocked(removedBuffers);
if (notifyBufferManager && mUseBufferManager && removedBuffers.size() > 0) {
- mBufferManager->onBuffersRemoved(getId(), getStreamSetId(), removedBuffers.size());
+ mBufferManager->onBuffersRemoved(getId(), getStreamSetId(), isMultiResolution(),
+ removedBuffers.size());
}
}
}
@@ -802,7 +809,7 @@
// Since device is already idle, there is no getBuffer call to buffer manager, unregister the
// stream at this point should be safe.
if (mUseBufferManager) {
- res = mBufferManager->unregisterStream(getId(), getStreamSetId());
+ res = mBufferManager->unregisterStream(getId(), getStreamSetId(), isMultiResolution());
if (res != OK) {
ALOGE("%s: Unable to unregister stream %d from buffer manager "
"(error %d %s)", __FUNCTION__, mId, res, strerror(-res));
@@ -914,7 +921,8 @@
ALOGV("Stream %d: Buffer released", stream->getId());
bool shouldFreeBuffer = false;
status_t res = stream->mBufferManager->onBufferReleased(
- stream->getId(), stream->getStreamSetId(), &shouldFreeBuffer);
+ stream->getId(), stream->getStreamSetId(), stream->isMultiResolution(),
+ &shouldFreeBuffer);
if (res != OK) {
ALOGE("%s: signaling buffer release to buffer manager failed: %s (%d).", __FUNCTION__,
strerror(-res), res);
@@ -927,7 +935,7 @@
stream->detachBufferLocked(&buffer, /*fenceFd*/ nullptr);
if (buffer.get() != nullptr) {
stream->mBufferManager->notifyBufferRemoved(
- stream->getId(), stream->getStreamSetId());
+ stream->getId(), stream->getStreamSetId(), stream->isMultiResolution());
}
}
}
@@ -945,7 +953,7 @@
stream->onBuffersRemovedLocked(buffers);
if (stream->mUseBufferManager) {
stream->mBufferManager->onBuffersRemoved(stream->getId(),
- stream->getStreamSetId(), buffers.size());
+ stream->getStreamSetId(), stream->isMultiResolution(), buffers.size());
}
ALOGV("Stream %d: %zu Buffers discarded.", stream->getId(), buffers.size());
}
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index 366d22a..c82f2a6 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -48,6 +48,7 @@
uint64_t combinedUsage;
size_t totalBufferCount;
bool isConfigured;
+ bool isMultiRes;
explicit StreamInfo(int id = CAMERA3_STREAM_ID_INVALID,
int setId = CAMERA3_STREAM_SET_ID_INVALID,
uint32_t w = 0,
@@ -56,7 +57,8 @@
android_dataspace ds = HAL_DATASPACE_UNKNOWN,
uint64_t usage = 0,
size_t bufferCount = 0,
- bool configured = false) :
+ bool configured = false,
+ bool multiRes = false) :
streamId(id),
streamSetId(setId),
width(w),
@@ -65,7 +67,8 @@
dataSpace(ds),
combinedUsage(usage),
totalBufferCount(bufferCount),
- isConfigured(configured){}
+ isConfigured(configured),
+ isMultiRes(multiRes) {}
};
/**
@@ -84,7 +87,7 @@
uint32_t width, uint32_t height, int format,
android_dataspace dataSpace, camera_stream_rotation_t rotation,
nsecs_t timestampOffset, const String8& physicalCameraId,
- int setId = CAMERA3_STREAM_SET_ID_INVALID);
+ int setId = CAMERA3_STREAM_SET_ID_INVALID, bool isMultiResolution = false);
/**
* Set up a stream for formats that have a variable buffer size for the same
@@ -96,7 +99,7 @@
uint32_t width, uint32_t height, size_t maxSize, int format,
android_dataspace dataSpace, camera_stream_rotation_t rotation,
nsecs_t timestampOffset, const String8& physicalCameraId,
- int setId = CAMERA3_STREAM_SET_ID_INVALID);
+ int setId = CAMERA3_STREAM_SET_ID_INVALID, bool isMultiResolution = false);
/**
* Set up a stream with deferred consumer for formats that have 2 dimensions, such as
@@ -107,7 +110,7 @@
uint64_t consumerUsage, android_dataspace dataSpace,
camera_stream_rotation_t rotation, nsecs_t timestampOffset,
const String8& physicalCameraId,
- int setId = CAMERA3_STREAM_SET_ID_INVALID);
+ int setId = CAMERA3_STREAM_SET_ID_INVALID, bool isMultiResolution = false);
virtual ~Camera3OutputStream();
@@ -232,7 +235,7 @@
android_dataspace dataSpace, camera_stream_rotation_t rotation,
const String8& physicalCameraId,
uint64_t consumerUsage = 0, nsecs_t timestampOffset = 0,
- int setId = CAMERA3_STREAM_SET_ID_INVALID);
+ int setId = CAMERA3_STREAM_SET_ID_INVALID, bool isMultiResolution = false);
/**
* Note that we release the lock briefly in this function
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.h b/services/camera/libcameraservice/device3/Camera3OutputUtils.h
index 772fe6e..142889a 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputUtils.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.h
@@ -46,6 +46,7 @@
uint32_t num_streams;
camera_stream_t **streams;
uint32_t operation_mode;
+ bool input_is_multi_resolution;
} camera_stream_configuration_t;
typedef struct camera_capture_request {
@@ -57,6 +58,8 @@
uint32_t num_physcam_settings;
const char **physcam_id;
const camera_metadata_t **physcam_settings;
+ int32_t input_width;
+ int32_t input_height;
} camera_capture_request_t;
typedef struct camera_capture_result {
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 4cb954e..c6e7002 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -49,7 +49,7 @@
camera_stream_type type,
uint32_t width, uint32_t height, size_t maxSize, int format,
android_dataspace dataSpace, camera_stream_rotation_t rotation,
- const String8& physicalCameraId, int setId) :
+ const String8& physicalCameraId, int setId, bool isMultiResolution) :
camera_stream(),
mId(id),
mSetId(setId),
@@ -73,7 +73,8 @@
mDataSpaceOverridden(false),
mOriginalDataSpace(dataSpace),
mPhysicalCameraId(physicalCameraId),
- mLastTimestamp(0) {
+ mLastTimestamp(0),
+ mIsMultiResolution(isMultiResolution) {
camera_stream::stream_type = type;
camera_stream::width = width;
@@ -99,6 +100,14 @@
return mSetId;
}
+int Camera3Stream::getHalStreamGroupId() const {
+ return mIsMultiResolution ? mSetId : -1;
+}
+
+bool Camera3Stream::isMultiResolution() const {
+ return mIsMultiResolution;
+}
+
uint32_t Camera3Stream::getWidth() const {
return camera_stream::width;
}
@@ -743,11 +752,16 @@
return res;
}
-status_t Camera3Stream::getInputBuffer(camera_stream_buffer *buffer, bool respectHalLimit) {
+status_t Camera3Stream::getInputBuffer(camera_stream_buffer *buffer,
+ Size* size, bool respectHalLimit) {
ATRACE_CALL();
Mutex::Autolock l(mLock);
status_t res = OK;
+ if (size == nullptr) {
+ ALOGE("%s: size must not be null", __FUNCTION__);
+ return BAD_VALUE;
+ }
// This function should be only called when the stream is configured already.
if (mState != STATE_CONFIGURED) {
ALOGE("%s: Stream %d: Can't get input buffers if stream is not in CONFIGURED state %d",
@@ -769,7 +783,7 @@
}
}
- res = getInputBufferLocked(buffer);
+ res = getInputBufferLocked(buffer, size);
if (res == OK) {
fireBufferListenersLocked(*buffer, /*acquired*/true, /*output*/false);
if (buffer->buffer) {
@@ -918,7 +932,7 @@
ALOGE("%s: This type of stream does not support output", __FUNCTION__);
return INVALID_OPERATION;
}
-status_t Camera3Stream::getInputBufferLocked(camera_stream_buffer *) {
+status_t Camera3Stream::getInputBufferLocked(camera_stream_buffer *, Size *) {
ALOGE("%s: This type of stream does not support input", __FUNCTION__);
return INVALID_OPERATION;
}
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index 55ed2f2..45d8478 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -147,6 +147,14 @@
* Get the output stream set id.
*/
int getStreamSetId() const;
+ /**
+ * Is this stream part of a multi-resolution stream set
+ */
+ bool isMultiResolution() const;
+ /**
+ * Get the HAL stream group id for a multi-resolution stream set
+ */
+ int getHalStreamGroupId() const;
/**
* Get the stream's dimensions and format
@@ -356,10 +364,13 @@
* For bidirectional streams, this method applies to the input-side
* buffers.
*
+ * This method also returns the size of the returned input buffer.
+ *
* Normally this call will block until the handed out buffer count is less than the stream
* max buffer count; if respectHalLimit is set to false, this is ignored.
*/
- status_t getInputBuffer(camera_stream_buffer *buffer, bool respectHalLimit = true);
+ status_t getInputBuffer(camera_stream_buffer *buffer,
+ Size* size, bool respectHalLimit = true);
/**
* Return a buffer to the stream after use by the HAL.
@@ -487,7 +498,7 @@
Camera3Stream(int id, camera_stream_type type,
uint32_t width, uint32_t height, size_t maxSize, int format,
android_dataspace dataSpace, camera_stream_rotation_t rotation,
- const String8& physicalCameraId, int setId);
+ const String8& physicalCameraId, int setId, bool isMultiResolution);
wp<Camera3StreamBufferFreedListener> mBufferFreedListener;
@@ -509,7 +520,7 @@
virtual status_t getBuffersLocked(std::vector<OutstandingBuffer>*);
- virtual status_t getInputBufferLocked(camera_stream_buffer *buffer);
+ virtual status_t getInputBufferLocked(camera_stream_buffer *buffer, Size* size);
virtual status_t returnInputBufferLocked(
const camera_stream_buffer &buffer);
@@ -608,6 +619,7 @@
String8 mPhysicalCameraId;
nsecs_t mLastTimestamp;
+ bool mIsMultiResolution = false;
bool mSupportOfflineProcessing = false;
}; // class Camera3Stream
diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
index c558b07..a567cb4 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
@@ -72,6 +72,12 @@
int release_fence;
} camera_stream_buffer_t;
+struct Size {
+ uint32_t width;
+ uint32_t height;
+ explicit Size(uint32_t w = 0, uint32_t h = 0) : width(w), height(h){}
+};
+
enum {
/**
* This stream set ID indicates that the set ID is invalid, and this stream doesn't intend to
@@ -352,7 +358,8 @@
* Normally this call will block until the handed out buffer count is less than the stream
* max buffer count; if respectHalLimit is set to false, this is ignored.
*/
- virtual status_t getInputBuffer(camera_stream_buffer *buffer, bool respectHalLimit = true) = 0;
+ virtual status_t getInputBuffer(camera_stream_buffer *buffer,
+ Size *size, bool respectHalLimit = true) = 0;
/**
* Return a buffer to the stream after use by the HAL.
diff --git a/services/camera/libcameraservice/libcameraservice_fuzzer/Android.bp b/services/camera/libcameraservice/libcameraservice_fuzzer/Android.bp
index d06b2c5..c7d7c4b 100644
--- a/services/camera/libcameraservice/libcameraservice_fuzzer/Android.bp
+++ b/services/camera/libcameraservice/libcameraservice_fuzzer/Android.bp
@@ -50,12 +50,14 @@
"android.hardware.camera.provider@2.4",
"android.hardware.camera.provider@2.5",
"android.hardware.camera.provider@2.6",
+ "android.hardware.camera.provider@2.7",
"android.hardware.camera.device@1.0",
"android.hardware.camera.device@3.2",
"android.hardware.camera.device@3.3",
"android.hardware.camera.device@3.4",
"android.hardware.camera.device@3.5",
"android.hardware.camera.device@3.6",
+ "android.hardware.camera.device@3.7",
],
fuzz_config: {
cc: [
diff --git a/services/camera/libcameraservice/tests/Android.mk b/services/camera/libcameraservice/tests/Android.mk
index b530342..0b5ad79 100644
--- a/services/camera/libcameraservice/tests/Android.mk
+++ b/services/camera/libcameraservice/tests/Android.mk
@@ -33,9 +33,11 @@
android.hardware.camera.provider@2.4 \
android.hardware.camera.provider@2.5 \
android.hardware.camera.provider@2.6 \
+ android.hardware.camera.provider@2.7 \
android.hardware.camera.device@1.0 \
android.hardware.camera.device@3.2 \
android.hardware.camera.device@3.4 \
+ android.hardware.camera.device@3.7 \
android.hidl.token@1.0-utils
LOCAL_STATIC_LIBRARIES := \
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
index c28f427..8f42a85 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
@@ -262,23 +262,24 @@
void SessionConfigurationUtils::mapStreamInfo(const OutputStreamInfo &streamInfo,
camera3::camera_stream_rotation_t rotation, String8 physicalId,
- hardware::camera::device::V3_4::Stream *stream /*out*/) {
+ int32_t groupId, hardware::camera::device::V3_7::Stream *stream /*out*/) {
if (stream == nullptr) {
return;
}
- stream->v3_2.streamType = hardware::camera::device::V3_2::StreamType::OUTPUT;
- stream->v3_2.width = streamInfo.width;
- stream->v3_2.height = streamInfo.height;
- stream->v3_2.format = Camera3Device::mapToPixelFormat(streamInfo.format);
+ stream->v3_4.v3_2.streamType = hardware::camera::device::V3_2::StreamType::OUTPUT;
+ stream->v3_4.v3_2.width = streamInfo.width;
+ stream->v3_4.v3_2.height = streamInfo.height;
+ stream->v3_4.v3_2.format = Camera3Device::mapToPixelFormat(streamInfo.format);
auto u = streamInfo.consumerUsage;
camera3::Camera3OutputStream::applyZSLUsageQuirk(streamInfo.format, &u);
- stream->v3_2.usage = Camera3Device::mapToConsumerUsage(u);
- stream->v3_2.dataSpace = Camera3Device::mapToHidlDataspace(streamInfo.dataSpace);
- stream->v3_2.rotation = Camera3Device::mapToStreamRotation(rotation);
- stream->v3_2.id = -1; // Invalid stream id
- stream->physicalCameraId = std::string(physicalId.string());
- stream->bufferSize = 0;
+ stream->v3_4.v3_2.usage = Camera3Device::mapToConsumerUsage(u);
+ stream->v3_4.v3_2.dataSpace = Camera3Device::mapToHidlDataspace(streamInfo.dataSpace);
+ stream->v3_4.v3_2.rotation = Camera3Device::mapToStreamRotation(rotation);
+ stream->v3_4.v3_2.id = -1; // Invalid stream id
+ stream->v3_4.physicalCameraId = std::string(physicalId.string());
+ stream->v3_4.bufferSize = 0;
+ stream->groupId = groupId;
}
binder::Status SessionConfigurationUtils::checkPhysicalCameraId(
@@ -358,7 +359,7 @@
const SessionConfiguration& sessionConfiguration,
const String8 &logicalCameraId, const CameraMetadata &deviceInfo,
metadataGetter getMetadata, const std::vector<std::string> &physicalCameraIds,
- hardware::camera::device::V3_4::StreamConfiguration &streamConfiguration, bool *earlyExit) {
+ hardware::camera::device::V3_7::StreamConfiguration &streamConfiguration, bool *earlyExit) {
auto operatingMode = sessionConfiguration.getOperatingMode();
binder::Status res = checkOperatingMode(operatingMode, deviceInfo, logicalCameraId);
@@ -393,14 +394,16 @@
streamConfiguration.streams.resize(streamCount);
size_t streamIdx = 0;
if (isInputValid) {
- streamConfiguration.streams[streamIdx++] = {{/*streamId*/0,
+ streamConfiguration.streams[streamIdx++] = {{{/*streamId*/0,
hardware::camera::device::V3_2::StreamType::INPUT,
static_cast<uint32_t> (sessionConfiguration.getInputWidth()),
static_cast<uint32_t> (sessionConfiguration.getInputHeight()),
Camera3Device::mapToPixelFormat(sessionConfiguration.getInputFormat()),
/*usage*/ 0, HAL_DATASPACE_UNKNOWN,
hardware::camera::device::V3_2::StreamRotation::ROTATION_0},
- /*physicalId*/ nullptr, /*bufferSize*/0};
+ /*physicalId*/ nullptr, /*bufferSize*/0}, /*groupId*/-1};
+ streamConfiguration.multiResolutionInputImage =
+ sessionConfiguration.inputIsMultiResolution();
}
for (const auto &it : outputConfigs) {
@@ -410,6 +413,7 @@
String8 physicalCameraId = String8(it.getPhysicalCameraId());
size_t numBufferProducers = bufferProducers.size();
bool isStreamInfoValid = false;
+ int32_t groupId = it.isMultiResolution() ? it.getSurfaceSetID() : -1;
OutputStreamInfo streamInfo;
res = checkSurfaceType(numBufferProducers, deferredConsumer, it.getSurfaceType());
@@ -432,7 +436,7 @@
if (surfaceType == OutputConfiguration::SURFACE_TYPE_SURFACE_VIEW) {
streamInfo.consumerUsage |= GraphicBuffer::USAGE_HW_COMPOSER;
}
- mapStreamInfo(streamInfo, camera3::CAMERA_STREAM_ROTATION_0, physicalCameraId,
+ mapStreamInfo(streamInfo, camera3::CAMERA_STREAM_ROTATION_0, physicalCameraId, groupId,
&streamConfiguration.streams[streamIdx++]);
isStreamInfoValid = true;
@@ -488,12 +492,13 @@
for (const auto& compositeStream : compositeStreams) {
mapStreamInfo(compositeStream,
static_cast<camera_stream_rotation_t> (it.getRotation()),
- physicalCameraId, &streamConfiguration.streams[streamIdx++]);
+ physicalCameraId, groupId,
+ &streamConfiguration.streams[streamIdx++]);
}
} else {
mapStreamInfo(streamInfo,
static_cast<camera_stream_rotation_t> (it.getRotation()),
- physicalCameraId, &streamConfiguration.streams[streamIdx++]);
+ physicalCameraId, groupId, &streamConfiguration.streams[streamIdx++]);
}
isStreamInfoValid = true;
}
@@ -503,4 +508,27 @@
}
+bool SessionConfigurationUtils::convertHALStreamCombinationFromV37ToV34(
+ hardware::camera::device::V3_4::StreamConfiguration &streamConfigV34,
+ const hardware::camera::device::V3_7::StreamConfiguration &streamConfigV37) {
+ if (streamConfigV37.multiResolutionInputImage) {
+ // ICameraDevice older than 3.7 doesn't support multi-resolution input image.
+ return false;
+ }
+
+ streamConfigV34.streams.resize(streamConfigV37.streams.size());
+ for (size_t i = 0; i < streamConfigV37.streams.size(); i++) {
+ if (streamConfigV37.streams[i].groupId != -1) {
+ // ICameraDevice older than 3.7 doesn't support multi-resolution output
+ // image
+ return false;
+ }
+ streamConfigV34.streams[i] = streamConfigV37.streams[i].v3_4;
+ }
+ streamConfigV34.operationMode = streamConfigV37.operationMode;
+ streamConfigV34.sessionParams = streamConfigV37.sessionParams;
+
+ return true;
+}
+
}// namespace android
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.h b/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
index 6ac7ab4..36e1dd7 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
@@ -21,7 +21,7 @@
#include <camera/camera2/OutputConfiguration.h>
#include <camera/camera2/SessionConfiguration.h>
#include <camera/camera2/SubmitInfo.h>
-#include <android/hardware/camera/device/3.4/ICameraDeviceSession.h>
+#include <android/hardware/camera/device/3.7/types.h>
#include <device3/Camera3StreamInterface.h>
@@ -53,8 +53,8 @@
const String8 &cameraId, const CameraMetadata &physicalCameraMetadata);
static void mapStreamInfo(const camera3::OutputStreamInfo &streamInfo,
- camera3::camera_stream_rotation_t rotation, String8 physicalId,
- hardware::camera::device::V3_4::Stream *stream /*out*/);
+ camera3::camera_stream_rotation_t rotation, String8 physicalId, int32_t groupId,
+ hardware::camera::device::V3_7::Stream *stream /*out*/);
// Check that the physicalCameraId passed in is spported by the camera
// device.
@@ -76,9 +76,16 @@
convertToHALStreamCombination(const SessionConfiguration& sessionConfiguration,
const String8 &cameraId, const CameraMetadata &deviceInfo,
metadataGetter getMetadata, const std::vector<std::string> &physicalCameraIds,
- hardware::camera::device::V3_4::StreamConfiguration &streamConfiguration,
+ hardware::camera::device::V3_7::StreamConfiguration &streamConfiguration,
bool *earlyExit);
+ // Utility function to convert a V3_7::StreamConfiguration to
+ // V3_4::StreamConfiguration. Return false if the original V3_7 configuration cannot
+ // be used by older version HAL.
+ static bool convertHALStreamCombinationFromV37ToV34(
+ hardware::camera::device::V3_4::StreamConfiguration &streamConfigV34,
+ const hardware::camera::device::V3_7::StreamConfiguration &streamConfigV37);
+
static const int32_t MAX_SURFACES_PER_STREAM = 4;
static const int32_t ROUNDING_WIDTH_CAP = 1920;
diff --git a/services/mediametrics/AudioAnalytics.cpp b/services/mediametrics/AudioAnalytics.cpp
index 9b7da0f..4ef87e4 100644
--- a/services/mediametrics/AudioAnalytics.cpp
+++ b/services/mediametrics/AudioAnalytics.cpp
@@ -138,24 +138,53 @@
"connection_count",
};
-// static constexpr const char * const AAudioStreamFields[] {
-// "mediametrics_aaudiostream_reported",
-// "caller_name",
-// "path",
-// "direction",
-// "frames_per_burst",
-// "buffer_size",
-// "buffer_capacity",
-// "channel_count",
-// "total_frames_transferred",
-// "perf_mode_requested",
-// "perf_mode_actual",
-// "sharing",
-// "xrun_count",
-// "device_type",
-// "format_app",
-// "format_device",
-// };
+static constexpr const char * const AAudioStreamFields[] {
+ "mediametrics_aaudiostream_reported",
+ "caller_name",
+ "path",
+ "direction",
+ "frames_per_burst",
+ "buffer_size",
+ "buffer_capacity",
+ "channel_count",
+ "total_frames_transferred",
+ "perf_mode_requested",
+ "perf_mode_actual",
+ "sharing",
+ "xrun_count",
+ "device_type",
+ "format_app",
+ "format_device",
+ "log_session_id",
+};
+
+/**
+ * printFields is a helper method that prints the fields and corresponding values
+ * in a human readable style.
+ */
+template <size_t N, typename ...Types>
+std::string printFields(const char * const (& fields)[N], Types ... args)
+{
+ std::stringstream ss;
+ ss << " { ";
+ stringutils::fieldPrint(ss, fields, args...);
+ ss << "}";
+ return ss.str();
+}
+
+/**
+ * sendToStatsd is a helper method that sends the arguments to statsd
+ */
+template <typename ...Types>
+int sendToStatsd(Types ... args)
+{
+ int result = 0;
+
+#ifdef STATSD_ENABLE
+ result = android::util::stats_write(args...);
+#endif
+ return result;
+}
/**
* sendToStatsd is a helper method that sends the arguments to statsd
@@ -387,7 +416,7 @@
} else {
ss << "Statsd atoms:\n" << statsd;
}
- ll -= n;
+ ll -= (int32_t)n;
}
}
@@ -793,7 +822,7 @@
mA2dpConnectionServiceNs = 0;
++mA2dpConnectionSuccesses;
- const auto connectionTimeMs = float(timeDiffNs * 1e-6);
+ const auto connectionTimeMs = float((double)timeDiffNs * 1e-6);
const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
"AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
@@ -951,7 +980,7 @@
mAudioAnalytics.mAnalyticsState->timeMachine().get(
key, AMEDIAMETRICS_PROP_UNDERRUN, &xrunCount);
- std::string deviceType;
+ std::string serializedDeviceTypes;
// TODO: only routed device id is logged, but no device type
int32_t formatApp = 0;
@@ -962,6 +991,9 @@
key, AMEDIAMETRICS_PROP_ENCODING, &formatDeviceStr);
const auto formatDevice = types::lookup<types::ENCODING, int32_t>(formatDeviceStr);
+ std::string logSessionId;
+ // TODO: log logSessionId
+
LOG(LOG_LEVEL) << "key:" << key
<< " caller_name:" << callerName << "(" << callerNameStr << ")"
<< " path:" << path
@@ -975,33 +1007,59 @@
<< " perf_mode_actual:" << perfModeActual
<< " sharing:" << sharingMode << "(" << sharingModeStr << ")"
<< " xrun_count:" << xrunCount
- << " device_type:" << deviceType
+ << " device_type:" << serializedDeviceTypes
<< " format_app:" << formatApp
- << " format_device: " << formatDevice << "(" << formatDeviceStr << ")";
+ << " format_device: " << formatDevice << "(" << formatDeviceStr << ")"
+ << " log_session_id: " << logSessionId;
- // TODO: send the metric to statsd when the proto is ready
- // if (mAudioAnalytics.mDeliverStatistics) {
- // const auto [ result, str ] = sendToStatsd(AAudioStreamFields,
- // CONDITION(android::util::MEDIAMETRICS_AAUDIOSTREAM_REPORTED)
- // , callerName
- // , path
- // , direction
- // , framesPerBurst
- // , bufferSizeInFrames
- // , bufferCapacityInFrames
- // , channelCount
- // , totalFramesTransferred
- // , perfModeRequested
- // , perfModeActual
- // , sharingMode
- // , xrunCount
- // , deviceType.c_str()
- // , formatApp
- // , formatDevice
- // );
- // ALOGV("%s: statsd %s", __func__, str.c_str());
- // mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
- // }
+ if (mAudioAnalytics.mDeliverStatistics) {
+ android::util::BytesField bf_serialized(
+ serializedDeviceTypes.c_str(), serializedDeviceTypes.size());
+ const auto result = sendToStatsd(
+ CONDITION(android::util::MEDIAMETRICS_AAUDIOSTREAM_REPORTED)
+ , callerName
+ , path
+ , direction
+ , framesPerBurst
+ , bufferSizeInFrames
+ , bufferCapacityInFrames
+ , channelCount
+ , totalFramesTransferred
+ , perfModeRequested
+ , perfModeActual
+ , sharingMode
+ , xrunCount
+ , bf_serialized
+ , formatApp
+ , formatDevice
+ , logSessionId.c_str()
+ );
+ std::stringstream ss;
+ ss << "result:" << result;
+ const auto fieldsStr = printFields(AAudioStreamFields,
+ CONDITION(android::util::MEDIAMETRICS_AAUDIOSTREAM_REPORTED)
+ , callerName
+ , path
+ , direction
+ , framesPerBurst
+ , bufferSizeInFrames
+ , bufferCapacityInFrames
+ , channelCount
+ , totalFramesTransferred
+ , perfModeRequested
+ , perfModeActual
+ , sharingMode
+ , xrunCount
+ , serializedDeviceTypes.c_str()
+ , formatApp
+ , formatDevice
+ , logSessionId.c_str()
+ );
+ ss << " " << fieldsStr;
+ std::string str = ss.str();
+ ALOGV("%s: statsd %s", __func__, str.c_str());
+ mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
+ }
}
} // namespace android::mediametrics
diff --git a/services/mediametrics/AudioPowerUsage.cpp b/services/mediametrics/AudioPowerUsage.cpp
index 34be0b9..e584f12 100644
--- a/services/mediametrics/AudioPowerUsage.cpp
+++ b/services/mediametrics/AudioPowerUsage.cpp
@@ -174,8 +174,8 @@
if (item_device == device && item_type == type) {
int64_t final_duration_ns = item_duration_ns + duration_ns;
double final_volume = (device & INPUT_DEVICE_BIT) ? 1.0:
- ((item_volume * item_duration_ns +
- average_vol * duration_ns) / final_duration_ns);
+ ((item_volume * (double)item_duration_ns +
+ average_vol * (double)duration_ns) / (double)final_duration_ns);
item->setInt64(AUDIO_POWER_USAGE_PROP_DURATION_NS, final_duration_ns);
item->setDouble(AUDIO_POWER_USAGE_PROP_VOLUME, final_volume);
@@ -289,7 +289,7 @@
const int64_t durationNs = endCallNs - mDeviceTimeNs;
if (durationNs > 0) {
mDeviceVolume = (mDeviceVolume * double(mVolumeTimeNs - mDeviceTimeNs) +
- mVoiceVolume * double(endCallNs - mVolumeTimeNs)) / durationNs;
+ mVoiceVolume * double(endCallNs - mVolumeTimeNs)) / (double)durationNs;
saveAsItems_l(mPrimaryDevice, durationNs, VOICE_CALL_TYPE, mDeviceVolume);
}
} else if (mode == "AUDIO_MODE_IN_CALL") { // entering call mode
@@ -317,7 +317,7 @@
const int64_t durationNs = timeNs - mDeviceTimeNs;
if (durationNs > 0) {
mDeviceVolume = (mDeviceVolume * double(mVolumeTimeNs - mDeviceTimeNs) +
- mVoiceVolume * double(timeNs - mVolumeTimeNs)) / durationNs;
+ mVoiceVolume * double(timeNs - mVolumeTimeNs)) / (double)durationNs;
mVolumeTimeNs = timeNs;
}
}
@@ -348,7 +348,7 @@
const int64_t durationNs = endDeviceNs - mDeviceTimeNs;
if (durationNs > 0) {
mDeviceVolume = (mDeviceVolume * double(mVolumeTimeNs - mDeviceTimeNs) +
- mVoiceVolume * double(endDeviceNs - mVolumeTimeNs)) / durationNs;
+ mVoiceVolume * double(endDeviceNs - mVolumeTimeNs)) / (double)durationNs;
saveAsItems_l(mPrimaryDevice, durationNs, VOICE_CALL_TYPE, mDeviceVolume);
}
// reset statistics
diff --git a/services/mediametrics/MediaMetricsService.cpp b/services/mediametrics/MediaMetricsService.cpp
index 9d380ec..1a0f6a4 100644
--- a/services/mediametrics/MediaMetricsService.cpp
+++ b/services/mediametrics/MediaMetricsService.cpp
@@ -108,7 +108,7 @@
{
ALOGD("%s", __func__);
// the class destructor clears anyhow, but we enforce clearing items first.
- mItemsDiscarded += mItems.size();
+ mItemsDiscarded += (int64_t)mItems.size();
mItems.clear();
}
@@ -288,7 +288,7 @@
std::lock_guard _l(mLock);
if (clear) {
- mItemsDiscarded += mItems.size();
+ mItemsDiscarded += (int64_t)mItems.size();
mItems.clear();
mAudioAnalytics.clear();
} else {
@@ -417,10 +417,10 @@
if (const size_t toErase = overlimit + expired;
toErase > 0) {
- mItemsDiscardedCount += overlimit;
- mItemsDiscardedExpire += expired;
- mItemsDiscarded += toErase;
- mItems.erase(mItems.begin(), mItems.begin() + toErase); // erase from front
+ mItemsDiscardedCount += (int64_t)overlimit;
+ mItemsDiscardedExpire += (int64_t)expired;
+ mItemsDiscarded += (int64_t)toErase;
+ mItems.erase(mItems.begin(), mItems.begin() + (ptrdiff_t)toErase); // erase from front
}
return more;
}
diff --git a/services/mediametrics/statsd_codec.cpp b/services/mediametrics/statsd_codec.cpp
index d502b30..1c5ab77 100644
--- a/services/mediametrics/statsd_codec.cpp
+++ b/services/mediametrics/statsd_codec.cpp
@@ -186,6 +186,16 @@
metrics_proto.set_lifetime_millis(lifetimeMs);
}
+ // new for S; need to plumb through to westworld
+ // android.media.mediacodec.channelCount int32
+ // android.media.mediacodec.sampleRate int32
+
+ // new for S; need to plumb through to westworld
+ // TODO PWG may want these fuzzed up a bit to obscure some precision
+ // android.media.mediacodec.vencode.bytes int64
+ // android.media.mediacodec.vencode.frames int64
+ // android.media.mediacodec.vencode.durationUs int64
+
std::string serialized;
if (!metrics_proto.SerializeToString(&serialized)) {
ALOGE("Failed to serialize codec metrics");
diff --git a/services/mediametrics/tests/Android.bp b/services/mediametrics/tests/Android.bp
index 71193a2..3baf739 100644
--- a/services/mediametrics/tests/Android.bp
+++ b/services/mediametrics/tests/Android.bp
@@ -11,6 +11,10 @@
name: "mediametrics_tests",
test_suites: ["device-tests"],
+ // not all shared libraries are populated in the 2nd architecture in
+ // particular, libmediametricsservice we use to have a tame copy of the service
+ compile_multilib: "first",
+
cflags: [
"-Wall",
"-Werror",
diff --git a/services/mediatranscoding/MediaTranscodingService.cpp b/services/mediatranscoding/MediaTranscodingService.cpp
index cca36fb..8b64134 100644
--- a/services/mediatranscoding/MediaTranscodingService.cpp
+++ b/services/mediatranscoding/MediaTranscodingService.cpp
@@ -24,6 +24,7 @@
#include <cutils/properties.h>
#include <media/TranscoderWrapper.h>
#include <media/TranscodingClientManager.h>
+#include <media/TranscodingLogger.h>
#include <media/TranscodingResourcePolicy.h>
#include <media/TranscodingSessionController.h>
#include <media/TranscodingThermalPolicy.h>
@@ -41,20 +42,49 @@
errorCode, \
String8::format("%s:%d: " errorString, __FUNCTION__, __LINE__, ##__VA_ARGS__))
-MediaTranscodingService::MediaTranscodingService(bool simulated)
+static constexpr int64_t kTranscoderHeartBeatIntervalUs = 1000000LL;
+
+MediaTranscodingService::MediaTranscodingService()
: mUidPolicy(new TranscodingUidPolicy()),
mResourcePolicy(new TranscodingResourcePolicy()),
- mThermalPolicy(new TranscodingThermalPolicy()) {
+ mThermalPolicy(new TranscodingThermalPolicy()),
+ mLogger(new TranscodingLogger()) {
ALOGV("MediaTranscodingService is created");
- mSessionController.reset(new TranscodingSessionController(
- [simulated](const std::shared_ptr<TranscoderCallbackInterface>& cb,
- int64_t heartBeatUs) -> std::shared_ptr<TranscoderInterface> {
- if (simulated) {
- return std::make_shared<SimulatedTranscoder>(cb, heartBeatUs);
- }
- return std::make_shared<TranscoderWrapper>(cb, heartBeatUs);
- },
- mUidPolicy, mResourcePolicy, mThermalPolicy));
+ bool simulated = property_get_bool("debug.transcoding.simulated_transcoder", false);
+ if (simulated) {
+ // Overrid default config params with shorter values for testing.
+ TranscodingSessionController::ControllerConfig config = {
+ .pacerBurstThresholdMs = 500,
+ .pacerBurstCountQuota = 10,
+ .pacerBurstTimeQuotaSeconds = 3,
+ };
+ mSessionController.reset(new TranscodingSessionController(
+ [](const std::shared_ptr<TranscoderCallbackInterface>& cb)
+ -> std::shared_ptr<TranscoderInterface> {
+ return std::make_shared<SimulatedTranscoder>(cb);
+ },
+ mUidPolicy, mResourcePolicy, mThermalPolicy, &config));
+ } else {
+ int32_t overrideBurstCountQuota =
+ property_get_int32("persist.transcoding.burst_count_quota", -1);
+ int32_t pacerBurstTimeQuotaSeconds =
+ property_get_int32("persist.transcoding.burst_time_quota_seconds", -1);
+ // Override default config params with properties if present.
+ TranscodingSessionController::ControllerConfig config;
+ if (overrideBurstCountQuota > 0) {
+ config.pacerBurstCountQuota = overrideBurstCountQuota;
+ }
+ if (pacerBurstTimeQuotaSeconds > 0) {
+ config.pacerBurstTimeQuotaSeconds = pacerBurstTimeQuotaSeconds;
+ }
+ mSessionController.reset(new TranscodingSessionController(
+ [logger = mLogger](const std::shared_ptr<TranscoderCallbackInterface>& cb)
+ -> std::shared_ptr<TranscoderInterface> {
+ return std::make_shared<TranscoderWrapper>(cb, logger,
+ kTranscoderHeartBeatIntervalUs);
+ },
+ mUidPolicy, mResourcePolicy, mThermalPolicy, &config));
+ }
mClientManager.reset(new TranscodingClientManager(mSessionController));
mUidPolicy->setCallback(mSessionController);
mResourcePolicy->setCallback(mSessionController);
@@ -100,8 +130,7 @@
//static
void MediaTranscodingService::instantiate() {
std::shared_ptr<MediaTranscodingService> service =
- ::ndk::SharedRefBase::make<MediaTranscodingService>(
- property_get_bool("debug.transcoding.simulated_transcoder", false));
+ ::ndk::SharedRefBase::make<MediaTranscodingService>();
binder_status_t status =
AServiceManager_addService(service->asBinder().get(), getServiceName());
if (status != STATUS_OK) {
diff --git a/services/mediatranscoding/MediaTranscodingService.h b/services/mediatranscoding/MediaTranscodingService.h
index d024c54..12be131 100644
--- a/services/mediatranscoding/MediaTranscodingService.h
+++ b/services/mediatranscoding/MediaTranscodingService.h
@@ -29,6 +29,7 @@
using ::aidl::android::media::TranscodingRequestParcel;
using ::aidl::android::media::TranscodingSessionParcel;
class TranscodingClientManager;
+class TranscodingLogger;
class TranscodingSessionController;
class UidPolicyInterface;
class ResourcePolicyInterface;
@@ -39,7 +40,7 @@
static constexpr int32_t kInvalidSessionId = -1;
static constexpr int32_t kInvalidClientId = -1;
- MediaTranscodingService(bool simulated);
+ MediaTranscodingService();
virtual ~MediaTranscodingService();
static void instantiate();
@@ -62,6 +63,7 @@
std::shared_ptr<UidPolicyInterface> mUidPolicy;
std::shared_ptr<ResourcePolicyInterface> mResourcePolicy;
std::shared_ptr<ThermalPolicyInterface> mThermalPolicy;
+ std::shared_ptr<TranscodingLogger> mLogger;
std::shared_ptr<TranscodingSessionController> mSessionController;
std::shared_ptr<TranscodingClientManager> mClientManager;
};
diff --git a/services/mediatranscoding/SimulatedTranscoder.cpp b/services/mediatranscoding/SimulatedTranscoder.cpp
index db83ccb..e80dbc5 100644
--- a/services/mediatranscoding/SimulatedTranscoder.cpp
+++ b/services/mediatranscoding/SimulatedTranscoder.cpp
@@ -47,8 +47,7 @@
return "(unknown)";
}
-SimulatedTranscoder::SimulatedTranscoder(const std::shared_ptr<TranscoderCallbackInterface>& cb,
- int64_t heartBeatUs __unused)
+SimulatedTranscoder::SimulatedTranscoder(const std::shared_ptr<TranscoderCallbackInterface>& cb)
: mCallback(cb), mLooperReady(false) {
ALOGV("SimulatedTranscoder CTOR: %p", this);
}
@@ -59,6 +58,7 @@
void SimulatedTranscoder::start(
ClientIdType clientId, SessionIdType sessionId, const TranscodingRequestParcel& request,
+ uid_t /*callingUid*/,
const std::shared_ptr<ITranscodingClientCallback>& /*clientCallback*/) {
{
auto lock = std::scoped_lock(mLock);
@@ -91,6 +91,7 @@
void SimulatedTranscoder::resume(
ClientIdType clientId, SessionIdType sessionId, const TranscodingRequestParcel& /*request*/,
+ uid_t /*callingUid*/,
const std::shared_ptr<ITranscodingClientCallback>& /*clientCallback*/) {
queueEvent(Event::Resume, clientId, sessionId, [=] {
auto callback = mCallback.lock();
@@ -130,7 +131,7 @@
void SimulatedTranscoder::threadLoop() {
bool running = false;
- std::chrono::system_clock::time_point lastRunningTime;
+ std::chrono::steady_clock::time_point lastRunningTime;
Event lastRunningEvent;
std::unique_lock<std::mutex> lock(mLock);
@@ -162,8 +163,9 @@
// Advance last running time and remaining time. This is needed to guard
// against bad events (which will be ignored) or spurious wakeups, in that
// case we don't want to wait for the same time again.
- auto now = std::chrono::system_clock::now();
- mRemainingTimeMap[key] -= (now - lastRunningTime);
+ auto now = std::chrono::steady_clock::now();
+ mRemainingTimeMap[key] -= std::chrono::duration_cast<std::chrono::microseconds>(
+ now - lastRunningTime);
lastRunningTime = now;
}
}
@@ -182,7 +184,7 @@
SessionKeyType key = std::make_pair(event.clientId, event.sessionId);
if (!running && (event.type == Event::Start || event.type == Event::Resume)) {
running = true;
- lastRunningTime = std::chrono::system_clock::now();
+ lastRunningTime = std::chrono::steady_clock::now();
lastRunningEvent = event;
ALOGV("%s: session {%lld, %d}: remaining time: %lld", __FUNCTION__,
(long long)event.clientId, event.sessionId,
@@ -193,7 +195,8 @@
if (event.type == Event::Stop) {
mRemainingTimeMap.erase(key);
} else {
- mRemainingTimeMap[key] -= (std::chrono::system_clock::now() - lastRunningTime);
+ mRemainingTimeMap[key] -= std::chrono::duration_cast<std::chrono::microseconds>(
+ std::chrono::steady_clock::now() - lastRunningTime);
}
} else {
ALOGW("%s: discarding bad event: session {%lld, %d}: %s", __FUNCTION__,
diff --git a/services/mediatranscoding/SimulatedTranscoder.h b/services/mediatranscoding/SimulatedTranscoder.h
index 010f0f0..58e2e30 100644
--- a/services/mediatranscoding/SimulatedTranscoder.h
+++ b/services/mediatranscoding/SimulatedTranscoder.h
@@ -49,17 +49,16 @@
static constexpr int64_t kSessionDurationUs = 1000000;
- SimulatedTranscoder(const std::shared_ptr<TranscoderCallbackInterface>& cb,
- int64_t heartBeatUs);
+ SimulatedTranscoder(const std::shared_ptr<TranscoderCallbackInterface>& cb);
~SimulatedTranscoder();
// TranscoderInterface
void start(ClientIdType clientId, SessionIdType sessionId,
- const TranscodingRequestParcel& request,
+ const TranscodingRequestParcel& request, uid_t callingUid,
const std::shared_ptr<ITranscodingClientCallback>& clientCallback) override;
void pause(ClientIdType clientId, SessionIdType sessionId) override;
void resume(ClientIdType clientId, SessionIdType sessionId,
- const TranscodingRequestParcel& request,
+ const TranscodingRequestParcel& request, uid_t callingUid,
const std::shared_ptr<ITranscodingClientCallback>& clientCallback) override;
void stop(ClientIdType clientId, SessionIdType sessionId, bool abandon = false) override;
// ~TranscoderInterface
diff --git a/services/mediatranscoding/tests/MediaTranscodingServiceTestHelper.h b/services/mediatranscoding/tests/MediaTranscodingServiceTestHelper.h
index 5256a3f..3f7d8d6 100644
--- a/services/mediatranscoding/tests/MediaTranscodingServiceTestHelper.h
+++ b/services/mediatranscoding/tests/MediaTranscodingServiceTestHelper.h
@@ -208,7 +208,9 @@
std::unique_lock lock(mLock);
mEventQueue.push_back(event);
- mLastErr = err;
+ if (err != TranscodingErrorCode::kNoError) {
+ mLastErrQueue.push_back(err);
+ }
mCondition.notify_one();
}
@@ -226,7 +228,12 @@
TranscodingErrorCode getLastError() {
std::unique_lock lock(mLock);
- return mLastErr;
+ if (mLastErrQueue.empty()) {
+ return TranscodingErrorCode::kNoError;
+ }
+ TranscodingErrorCode err = mLastErrQueue.front();
+ mLastErrQueue.pop_front();
+ return err;
}
private:
@@ -234,7 +241,7 @@
std::condition_variable mCondition;
Event mPoppedEvent;
std::list<Event> mEventQueue;
- TranscodingErrorCode mLastErr;
+ std::list<TranscodingErrorCode> mLastErrQueue;
int mUpdateCount = 0;
int mLastProgress = -1;
};
diff --git a/services/mediatranscoding/tests/mediatranscodingservice_simulated_tests.cpp b/services/mediatranscoding/tests/mediatranscodingservice_simulated_tests.cpp
index b8a6f76..c8994ac 100644
--- a/services/mediatranscoding/tests/mediatranscodingservice_simulated_tests.cpp
+++ b/services/mediatranscoding/tests/mediatranscodingservice_simulated_tests.cpp
@@ -54,6 +54,10 @@
constexpr int64_t kPaddingUs = 1000000;
constexpr int64_t kSessionWithPaddingUs = SimulatedTranscoder::kSessionDurationUs + kPaddingUs;
constexpr int64_t kWatchdogTimeoutUs = 3000000;
+// Pacer settings used for simulated tests. Listed here for reference.
+constexpr int32_t kSimulatedPacerBurstThresholdMs = 500;
+//constexpr int32_t kSimulatedPacerBurstCountQuota = 10;
+//constexpr int32_t kSimulatedPacerBurstTimeQuotaSec = 3;
constexpr const char* kClientOpPackageName = "TestClientPackage";
@@ -64,6 +68,25 @@
virtual ~MediaTranscodingServiceSimulatedTest() {
ALOGI("MediaTranscodingServiceResourceTest destroyed");
}
+
+ void testPacerHelper(int numSubmits, int sessionDurationMs, int expectedSuccess) {
+ // Idle to clear out burst history.
+ usleep(kSimulatedPacerBurstThresholdMs * 2 * 1000);
+ for (int i = 0; i < numSubmits; i++) {
+ EXPECT_TRUE(mClient3->submit(i, "test_source_file_0", "test_destination_file_0",
+ TranscodingSessionPriority::kNormal, -1 /*bitrateBps*/,
+ -1 /*overridePid*/, -1 /*overrideUid*/,
+ sessionDurationMs));
+ }
+ for (int i = 0; i < expectedSuccess; i++) {
+ EXPECT_EQ(mClient3->pop(kPaddingUs), EventTracker::Start(CLIENT(3), i));
+ EXPECT_EQ(mClient3->pop(kSessionWithPaddingUs), EventTracker::Finished(CLIENT(3), i));
+ }
+ for (int i = expectedSuccess; i < numSubmits; i++) {
+ EXPECT_EQ(mClient3->pop(kPaddingUs), EventTracker::Failed(CLIENT(3), i));
+ EXPECT_EQ(mClient3->getLastError(), TranscodingErrorCode::kDroppedByService);
+ }
+ }
};
TEST_F(MediaTranscodingServiceSimulatedTest, TestRegisterNullClient) {
@@ -414,5 +437,36 @@
ALOGD("TestTranscodingWatchdog finished.");
}
+TEST_F(MediaTranscodingServiceSimulatedTest, TestTranscodingPacerOverCountQuotaOnly) {
+ ALOGD("TestTranscodingPacerOverCountQuotaOnly starting...");
+
+ registerMultipleClients();
+ testPacerHelper(12 /*numSubmits*/, 100 /*sessionDurationMs*/, 12 /*expectedSuccess*/);
+ unregisterMultipleClients();
+
+ ALOGD("TestTranscodingPacerOverCountQuotaOnly finished.");
+}
+
+TEST_F(MediaTranscodingServiceSimulatedTest, TestTranscodingPacerOverTimeQuotaOnly) {
+ ALOGD("TestTranscodingPacerOverTimeQuotaOnly starting...");
+
+ registerMultipleClients();
+ testPacerHelper(5 /*numSubmits*/, 1000 /*sessionDurationMs*/, 5 /*expectedSuccess*/);
+ unregisterMultipleClients();
+
+ ALOGD("TestTranscodingPacerOverTimeQuotaOnly finished.");
+}
+
+TEST_F(MediaTranscodingServiceSimulatedTest, TestTranscodingPacerOverQuota) {
+ ALOGD("TestTranscodingPacerOverQuota starting...");
+
+ registerMultipleClients();
+ testPacerHelper(12 /*numSubmits*/, 400 /*sessionDurationMs*/, 10 /*expectedSuccess*/);
+ unregisterMultipleClients();
+
+ // Idle to clear out burst history. Since we expect it to actually fail, wait for cooldown.
+ ALOGD("TestTranscodingPacerOverQuota finished.");
+}
+
} // namespace media
} // namespace android
diff --git a/services/oboeservice/AAudioEndpointManager.cpp b/services/oboeservice/AAudioEndpointManager.cpp
index 407f6d5..3224cfc 100644
--- a/services/oboeservice/AAudioEndpointManager.cpp
+++ b/services/oboeservice/AAudioEndpointManager.cpp
@@ -24,6 +24,7 @@
#include <mutex>
#include <sstream>
#include <utility/AAudioUtilities.h>
+#include <media/AidlConversion.h>
#include "AAudioClientTracker.h"
#include "AAudioEndpointManager.h"
@@ -182,7 +183,9 @@
// and START calls. This will help preserve app compatibility.
// An app can avoid having this happen by closing their streams when
// the app is paused.
- AAudioClientTracker::getInstance().setExclusiveEnabled(request.getProcessId(), false);
+ pid_t pid = VALUE_OR_FATAL(
+ aidl2legacy_int32_t_pid_t(request.getIdentity().pid));
+ AAudioClientTracker::getInstance().setExclusiveEnabled(pid, false);
endpointToSteal = endpoint; // return it to caller
}
return nullptr;
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index 69e58f6..0b69bf6 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -22,7 +22,9 @@
#include <iostream>
#include <sstream>
+#include <android/media/permission/Identity.h>
#include <aaudio/AAudio.h>
+#include <media/AidlConversion.h>
#include <mediautils/ServiceUtilities.h>
#include <utils/String16.h>
@@ -37,18 +39,26 @@
using namespace aaudio;
#define MAX_STREAMS_PER_PROCESS 8
-#define AIDL_RETURN(x) *_aidl_return = (x); return Status::ok();
+#define AIDL_RETURN(x) { *_aidl_return = (x); return Status::ok(); }
+#define VALUE_OR_RETURN_ILLEGAL_ARG_STATUS(x) \
+ ({ auto _tmp = (x); \
+ if (!_tmp.ok()) AIDL_RETURN(AAUDIO_ERROR_ILLEGAL_ARGUMENT); \
+ std::move(_tmp.value()); })
using android::AAudioService;
+using android::media::permission::Identity;
using binder::Status;
android::AAudioService::AAudioService()
: BnAAudioService(),
mAdapter(this) {
- mAudioClient.clientUid = getuid(); // TODO consider using geteuid()
- mAudioClient.clientPid = getpid();
- mAudioClient.packageName = String16("");
+ // TODO consider using geteuid()
+ // TODO b/182392769: use identity util
+ mAudioClient.identity.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(getuid()));
+ mAudioClient.identity.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(getpid()));
+ mAudioClient.identity.packageName = std::nullopt;
+ mAudioClient.identity.attributionTag = std::nullopt;
AAudioClientTracker::getInstance().setAAudioService(this);
}
@@ -105,8 +115,13 @@
aaudio_sharing_mode_t sharingMode = configurationInput.getSharingMode();
// Enforce limit on client processes.
- pid_t pid = request.getProcessId();
- if (pid != mAudioClient.clientPid) {
+ Identity callingIdentity = request.getIdentity();
+ pid_t pid = IPCThreadState::self()->getCallingPid();
+ callingIdentity.pid = VALUE_OR_RETURN_ILLEGAL_ARG_STATUS(
+ legacy2aidl_pid_t_int32_t(pid));
+ callingIdentity.uid = VALUE_OR_RETURN_ILLEGAL_ARG_STATUS(
+ legacy2aidl_uid_t_int32_t(IPCThreadState::self()->getCallingUid()));
+ if (callingIdentity.pid != mAudioClient.identity.pid) {
int32_t count = AAudioClientTracker::getInstance().getStreamCount(pid);
if (count >= MAX_STREAMS_PER_PROCESS) {
ALOGE("openStream(): exceeded max streams per process %d >= %d",
@@ -121,7 +136,7 @@
}
if (sharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE
- && AAudioClientTracker::getInstance().isExclusiveEnabled(request.getProcessId())) {
+ && AAudioClientTracker::getInstance().isExclusiveEnabled(pid)) {
// only trust audioserver for in service indication
bool inService = false;
if (isCallerInService()) {
@@ -154,7 +169,6 @@
} else {
aaudio_handle_t handle = mStreamTracker.addStreamForHandle(serviceStream.get());
serviceStream->setHandle(handle);
- pid_t pid = request.getProcessId();
AAudioClientTracker::getInstance().registerClientStream(pid, serviceStream);
paramsOut.copyFrom(*serviceStream);
*_paramsOut = std::move(paramsOut).parcelable();
@@ -266,8 +280,10 @@
}
bool AAudioService::isCallerInService() {
- return mAudioClient.clientPid == IPCThreadState::self()->getCallingPid() &&
- mAudioClient.clientUid == IPCThreadState::self()->getCallingUid();
+ pid_t clientPid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(mAudioClient.identity.pid));
+ uid_t clientUid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(mAudioClient.identity.uid));
+ return clientPid == IPCThreadState::self()->getCallingPid() &&
+ clientUid == IPCThreadState::self()->getCallingUid();
}
aaudio_result_t AAudioService::closeStream(sp<AAudioServiceStreamBase> serviceStream) {
@@ -290,9 +306,11 @@
// Only allow owner or the aaudio service to access the stream.
const uid_t callingUserId = IPCThreadState::self()->getCallingUid();
const uid_t ownerUserId = serviceStream->getOwnerUserId();
+ const uid_t clientUid = VALUE_OR_FATAL(
+ aidl2legacy_int32_t_uid_t(mAudioClient.identity.uid));
bool callerOwnsIt = callingUserId == ownerUserId;
- bool serverCalling = callingUserId == mAudioClient.clientUid;
- bool serverOwnsIt = ownerUserId == mAudioClient.clientUid;
+ bool serverCalling = callingUserId == clientUid;
+ bool serverOwnsIt = ownerUserId == clientUid;
bool allowed = callerOwnsIt || serverCalling || serverOwnsIt;
if (!allowed) {
ALOGE("AAudioService: calling uid %d cannot access stream 0x%08X owned by %d",
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
index 85b2057..556710d 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -73,9 +73,12 @@
aaudio_result_t AAudioServiceEndpointMMAP::open(const aaudio::AAudioStreamRequest &request) {
aaudio_result_t result = AAUDIO_OK;
copyFrom(request.getConstantConfiguration());
- mMmapClient.clientUid = request.getUserId();
- mMmapClient.clientPid = request.getProcessId();
- mMmapClient.packageName.setTo(String16(""));
+ mMmapClient.identity = request.getIdentity();
+ // TODO b/182392769: use identity util
+ mMmapClient.identity.uid = VALUE_OR_FATAL(
+ legacy2aidl_uid_t_int32_t(IPCThreadState::self()->getCallingUid()));
+ mMmapClient.identity.pid = VALUE_OR_FATAL(
+ legacy2aidl_pid_t_int32_t(IPCThreadState::self()->getCallingPid()));
audio_format_t audioFormat = getFormat();
@@ -159,8 +162,8 @@
this, // callback
mMmapStream,
&mPortHandle);
- ALOGD("%s() mMapClient.uid = %d, pid = %d => portHandle = %d\n",
- __func__, mMmapClient.clientUid, mMmapClient.clientPid, mPortHandle);
+ ALOGD("%s() mMapClient.identity = %s => portHandle = %d\n",
+ __func__, mMmapClient.identity.toString().c_str(), mPortHandle);
if (status != OK) {
// This can happen if the resource is busy or the config does
// not match the hardware.
@@ -208,8 +211,9 @@
setBufferCapacity(mMmapBufferinfo.buffer_size_frames);
if (!isBufferShareable) {
// Exclusive mode can only be used by the service because the FD cannot be shared.
- uid_t audioServiceUid = getuid();
- if ((mMmapClient.clientUid != audioServiceUid) &&
+ int32_t audioServiceUid =
+ VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(getuid()));
+ if ((mMmapClient.identity.uid != audioServiceUid) &&
getSharingMode() == AAUDIO_SHARING_MODE_EXCLUSIVE) {
ALOGW("%s() - exclusive FD cannot be used by client", __func__);
result = AAUDIO_ERROR_UNAVAILABLE;
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index 7edc25c..694094c 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -39,6 +39,8 @@
using namespace android; // TODO just import names needed
using namespace aaudio; // TODO just import names needed
+using media::permission::Identity;
+
/**
* Base class for streams in the service.
* @return
@@ -48,9 +50,7 @@
: mTimestampThread("AATime")
, mAtomicStreamTimestamp()
, mAudioService(audioService) {
- mMmapClient.clientUid = -1;
- mMmapClient.clientPid = -1;
- mMmapClient.packageName = String16("");
+ mMmapClient.identity = Identity();
}
AAudioServiceStreamBase::~AAudioServiceStreamBase() {
@@ -82,7 +82,7 @@
result << " 0x" << std::setfill('0') << std::setw(8) << std::hex << mHandle
<< std::dec << std::setfill(' ') ;
- result << std::setw(6) << mMmapClient.clientUid;
+ result << std::setw(6) << mMmapClient.identity.uid;
result << std::setw(7) << mClientHandle;
result << std::setw(4) << (isRunning() ? "yes" : " no");
result << std::setw(6) << getState();
@@ -128,9 +128,12 @@
AAudioEndpointManager &mEndpointManager = AAudioEndpointManager::getInstance();
aaudio_result_t result = AAUDIO_OK;
- mMmapClient.clientUid = request.getUserId();
- mMmapClient.clientPid = request.getProcessId();
- mMmapClient.packageName.setTo(String16("")); // TODO What should we do here?
+ mMmapClient.identity = request.getIdentity();
+ // TODO b/182392769: use identity util
+ mMmapClient.identity.uid = VALUE_OR_FATAL(
+ legacy2aidl_uid_t_int32_t(IPCThreadState::self()->getCallingUid()));
+ mMmapClient.identity.pid = VALUE_OR_FATAL(
+ legacy2aidl_pid_t_int32_t(IPCThreadState::self()->getCallingPid()));
// Limit scope of lock to avoid recursive lock in close().
{
diff --git a/services/oboeservice/AAudioServiceStreamBase.h b/services/oboeservice/AAudioServiceStreamBase.h
index 0f752b7..06c9f21 100644
--- a/services/oboeservice/AAudioServiceStreamBase.h
+++ b/services/oboeservice/AAudioServiceStreamBase.h
@@ -21,6 +21,7 @@
#include <mutex>
#include <android-base/thread_annotations.h>
+#include <media/AidlConversion.h>
#include <media/AudioClient.h>
#include <utils/RefBase.h>
@@ -159,11 +160,11 @@
}
uid_t getOwnerUserId() const {
- return mMmapClient.clientUid;
+ return VALUE_OR_FATAL(android::aidl2legacy_int32_t_uid_t(mMmapClient.identity.uid));
}
pid_t getOwnerProcessId() const {
- return mMmapClient.clientPid;
+ return VALUE_OR_FATAL(android::aidl2legacy_int32_t_pid_t(mMmapClient.identity.pid));
}
aaudio_handle_t getHandle() const {
diff --git a/services/oboeservice/Android.bp b/services/oboeservice/Android.bp
index 21f3247..a419dd5 100644
--- a/services/oboeservice/Android.bp
+++ b/services/oboeservice/Android.bp
@@ -66,10 +66,13 @@
"liblog",
"libutils",
"aaudio-aidl-cpp",
+ "media_permission-aidl-cpp",
+ "libaudioclient_aidl_conversion",
],
export_shared_lib_headers: [
"libaaudio_internal",
+ "media_permission-aidl-cpp",
],
header_libs: [
diff --git a/services/oboeservice/fuzzer/Android.bp b/services/oboeservice/fuzzer/Android.bp
new file mode 100644
index 0000000..f4e8a81
--- /dev/null
+++ b/services/oboeservice/fuzzer/Android.bp
@@ -0,0 +1,72 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2020 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.
+ *
+ *****************************************************************************
+ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
+ */
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_av_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_av_license"],
+}
+
+cc_fuzz {
+ name: "oboeservice_fuzzer",
+ srcs: [
+ "oboeservice_fuzzer.cpp",
+ ],
+ shared_libs: [
+ "libaaudio_internal",
+ "libaudioclient",
+ "libaudioflinger",
+ "libaudioutils",
+ "libmedia_helper",
+ "libmediametrics",
+ "libmediautils",
+ "libbase",
+ "libbinder",
+ "libcutils",
+ "liblog",
+ "libutils",
+ "aaudio-aidl-cpp",
+ "media_permission-aidl-cpp",
+ "libaudioclient_aidl_conversion",
+ ],
+ static_libs: [
+ "libaaudioservice",
+ ],
+ include_dirs: [
+ "frameworks/av/services/oboeservice",
+ ],
+ header_libs: [
+ "libaudiohal_headers",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-unused-parameter",
+ ],
+ fuzz_config: {
+ cc: [
+ "android-media-fuzzing-reports@google.com",
+ ],
+ componentid: 155276,
+ },
+}
diff --git a/services/oboeservice/fuzzer/README.md b/services/oboeservice/fuzzer/README.md
new file mode 100644
index 0000000..00b85df
--- /dev/null
+++ b/services/oboeservice/fuzzer/README.md
@@ -0,0 +1,65 @@
+# Fuzzer for libaaudioservice
+
+## Plugin Design Considerations
+The fuzzer plugin for libaaudioservice is designed based on the
+understanding of the service and tries to achieve the following:
+
+##### Maximize code coverage
+The configuration parameters are not hardcoded, but instead selected based on
+incoming data. This ensures more code paths are reached by the fuzzer.
+
+AAudio Service request contains the following parameters:
+1. AAudioFormat
+2. UserId
+3. ProcessId
+4. InService
+5. DeviceId
+6. SampleRate
+7. SamplesPerFrame
+8. Direction
+9. SharingMode
+10. Usage
+11. ContentType
+12. InputPreset
+13. BufferCapacity
+
+| Parameter| Valid Input Values| Configured Value|
+|------------- |-------------| ----- |
+| `AAudioFormat` | `AAUDIO_FORMAT_UNSPECIFIED`, `AAUDIO_FORMAT_PCM_I16`, `AAUDIO_FORMAT_PCM_FLOAT` | Value chosen from valid values by obtaining index from FuzzedDataProvider |
+| `UserId` | `INT32_MIN` to `INT32_MAX` | Value obtained from getuid() |
+| `ProcessId` | `INT32_MIN` to `INT32_MAX` | Value obtained from getpid() |
+| `InService` | `bool` | Value obtained from FuzzedDataProvider |
+| `DeviceId` | `INT32_MIN` to `INT32_MAX` | Value obtained from FuzzedDataProvider |
+| `SampleRate` | `INT32_MIN` to `INT32_MAX` | Value obtained from FuzzedDataProvider |
+| `SamplesPerFrame` | `INT32_MIN` to `INT32_MAX` | Value obtained from FuzzedDataProvider |
+| `Direction` | `AAUDIO_DIRECTION_OUTPUT`, `AAUDIO_DIRECTION_INPUT` | Value chosen from valid values by obtaining index from FuzzedDataProvider |
+| `SharingMode` | `AAUDIO_SHARING_MODE_EXCLUSIVE`, `AAUDIO_SHARING_MODE_SHARED` | Value chosen from valid values by obtaining index from FuzzedDataProvider |
+| `Usage` | `AAUDIO_USAGE_MEDIA`, `AAUDIO_USAGE_VOICE_COMMUNICATION`, `AAUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING`, `AAUDIO_USAGE_ALARM`, `AAUDIO_USAGE_NOTIFICATION`, `AAUDIO_USAGE_NOTIFICATION_RINGTONE`, `AAUDIO_USAGE_NOTIFICATION_EVENT`, `AAUDIO_USAGE_ASSISTANCE_ACCESSIBILITY`, `AAUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE`, `AAUDIO_USAGE_ASSISTANCE_SONIFICATION`, `AAUDIO_USAGE_GAME`, `AAUDIO_USAGE_ASSISTANT`, `AAUDIO_SYSTEM_USAGE_EMERGENCY`, `AAUDIO_SYSTEM_USAGE_SAFETY`, `AAUDIO_SYSTEM_USAGE_VEHICLE_STATUS`, `AAUDIO_SYSTEM_USAGE_ANNOUNCEMENT` | Value chosen from valid values by obtaining index from FuzzedDataProvider |
+| `ContentType` | `AAUDIO_CONTENT_TYPE_SPEECH`, `AAUDIO_CONTENT_TYPE_MUSIC`, `AAUDIO_CONTENT_TYPE_MOVIE`, `AAUDIO_CONTENT_TYPE_SONIFICATION` | Value chosen from valid values by obtaining index from FuzzedDataProvider |
+| `InputPreset` | `AAUDIO_INPUT_PRESET_GENERIC`, `AAUDIO_INPUT_PRESET_CAMCORDER`, `AAUDIO_INPUT_PRESET_VOICE_RECOGNITION`, `AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION`, `AAUDIO_INPUT_PRESET_UNPROCESSED`, `AAUDIO_INPUT_PRESET_VOICE_PERFORMANCE` | Value chosen from valid values by obtaining index from FuzzedDataProvider |
+| `BufferCapacity` | `INT32_MIN` to `INT32_MAX` | Value obtained from FuzzedDataProvider |
+
+This also ensures that the plugin is always deterministic for any given input.
+
+## Build
+
+This describes steps to build oboeservice_fuzzer binary.
+
+### Android
+
+#### Steps to build
+Build the fuzzer
+```
+ $ mm -j$(nproc) oboeservice_fuzzer
+```
+
+#### Steps to run
+To run on device
+```
+ $ adb sync data
+ $ adb shell /data/fuzz/arm64/oboeservice_fuzzer/oboeservice_fuzzer
+```
+
+## References:
+ * http://llvm.org/docs/LibFuzzer.html
+ * https://github.com/google/oss-fuzz
diff --git a/services/oboeservice/fuzzer/oboeservice_fuzzer.cpp b/services/oboeservice/fuzzer/oboeservice_fuzzer.cpp
new file mode 100644
index 0000000..8e508d3
--- /dev/null
+++ b/services/oboeservice/fuzzer/oboeservice_fuzzer.cpp
@@ -0,0 +1,369 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2020 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.
+ *
+ *****************************************************************************
+ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
+ */
+#include <fuzzer/FuzzedDataProvider.h>
+#include <stdio.h>
+
+#include <AAudioService.h>
+#include <aaudio/AAudio.h>
+#include "aaudio/BnAAudioClient.h"
+#include <android/media/permission/Identity.h>
+
+#define UNUSED_PARAM __attribute__((unused))
+
+using namespace android;
+using namespace aaudio;
+
+aaudio_format_t kAAudioFormats[] = {
+ AAUDIO_FORMAT_UNSPECIFIED,
+ AAUDIO_FORMAT_PCM_I16,
+ AAUDIO_FORMAT_PCM_FLOAT,
+};
+
+aaudio_usage_t kAAudioUsages[] = {
+ AAUDIO_USAGE_MEDIA,
+ AAUDIO_USAGE_VOICE_COMMUNICATION,
+ AAUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING,
+ AAUDIO_USAGE_ALARM,
+ AAUDIO_USAGE_NOTIFICATION,
+ AAUDIO_USAGE_NOTIFICATION_RINGTONE,
+ AAUDIO_USAGE_NOTIFICATION_EVENT,
+ AAUDIO_USAGE_ASSISTANCE_ACCESSIBILITY,
+ AAUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
+ AAUDIO_USAGE_ASSISTANCE_SONIFICATION,
+ AAUDIO_USAGE_GAME,
+ AAUDIO_USAGE_ASSISTANT,
+ AAUDIO_SYSTEM_USAGE_EMERGENCY,
+ AAUDIO_SYSTEM_USAGE_SAFETY,
+ AAUDIO_SYSTEM_USAGE_VEHICLE_STATUS,
+ AAUDIO_SYSTEM_USAGE_ANNOUNCEMENT,
+};
+
+aaudio_content_type_t kAAudioContentTypes[] = {
+ AAUDIO_CONTENT_TYPE_SPEECH,
+ AAUDIO_CONTENT_TYPE_MUSIC,
+ AAUDIO_CONTENT_TYPE_MOVIE,
+ AAUDIO_CONTENT_TYPE_SONIFICATION,
+};
+
+aaudio_input_preset_t kAAudioInputPresets[] = {
+ AAUDIO_INPUT_PRESET_GENERIC, AAUDIO_INPUT_PRESET_CAMCORDER,
+ AAUDIO_INPUT_PRESET_VOICE_RECOGNITION, AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION,
+ AAUDIO_INPUT_PRESET_UNPROCESSED, AAUDIO_INPUT_PRESET_VOICE_PERFORMANCE,
+};
+
+const size_t kNumAAudioFormats = std::size(kAAudioFormats);
+const size_t kNumAAudioUsages = std::size(kAAudioUsages);
+const size_t kNumAAudioContentTypes = std::size(kAAudioContentTypes);
+const size_t kNumAAudioInputPresets = std::size(kAAudioInputPresets);
+
+class FuzzAAudioClient : public virtual RefBase, public AAudioServiceInterface {
+ public:
+ FuzzAAudioClient(sp<AAudioService> service);
+
+ virtual ~FuzzAAudioClient();
+
+ AAudioServiceInterface *getAAudioService();
+
+ void dropAAudioService();
+
+ void registerClient(const sp<IAAudioClient> &client UNUSED_PARAM) override {}
+
+ aaudio_handle_t openStream(const AAudioStreamRequest &request,
+ AAudioStreamConfiguration &configurationOutput) override;
+
+ aaudio_result_t closeStream(aaudio_handle_t streamHandle) override;
+
+ aaudio_result_t getStreamDescription(aaudio_handle_t streamHandle,
+ AudioEndpointParcelable &parcelable) override;
+
+ aaudio_result_t startStream(aaudio_handle_t streamHandle) override;
+
+ aaudio_result_t pauseStream(aaudio_handle_t streamHandle) override;
+
+ aaudio_result_t stopStream(aaudio_handle_t streamHandle) override;
+
+ aaudio_result_t flushStream(aaudio_handle_t streamHandle) override;
+
+ aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle, pid_t clientThreadId,
+ int64_t periodNanoseconds) override;
+
+ aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
+ pid_t clientThreadId) override;
+
+ aaudio_result_t startClient(aaudio_handle_t streamHandle UNUSED_PARAM,
+ const AudioClient &client UNUSED_PARAM,
+ const audio_attributes_t *attr UNUSED_PARAM,
+ audio_port_handle_t *clientHandle UNUSED_PARAM) override {
+ return AAUDIO_ERROR_UNAVAILABLE;
+ }
+
+ aaudio_result_t stopClient(aaudio_handle_t streamHandle UNUSED_PARAM,
+ audio_port_handle_t clientHandle UNUSED_PARAM) override {
+ return AAUDIO_ERROR_UNAVAILABLE;
+ }
+
+ void onStreamChange(aaudio_handle_t handle, int32_t opcode, int32_t value) {}
+
+ int getDeathCount() { return mDeathCount; }
+
+ void incDeathCount() { ++mDeathCount; }
+
+ class AAudioClient : public IBinder::DeathRecipient, public BnAAudioClient {
+ public:
+ AAudioClient(wp<FuzzAAudioClient> fuzzAAudioClient) : mBinderClient(fuzzAAudioClient) {}
+
+ virtual void binderDied(const wp<IBinder> &who UNUSED_PARAM) {
+ sp<FuzzAAudioClient> client = mBinderClient.promote();
+ if (client.get()) {
+ client->dropAAudioService();
+ client->incDeathCount();
+ }
+ }
+
+ android::binder::Status onStreamChange(int32_t handle, int32_t opcode, int32_t value) {
+ static_assert(std::is_same_v<aaudio_handle_t, int32_t>);
+ android::sp<FuzzAAudioClient> client = mBinderClient.promote();
+ if (client.get() != nullptr) {
+ client->onStreamChange(handle, opcode, value);
+ }
+ return android::binder::Status::ok();
+ }
+
+ private:
+ wp<FuzzAAudioClient> mBinderClient;
+ };
+
+ private:
+ sp<AAudioService> mAAudioService;
+ sp<AAudioClient> mAAudioClient;
+ AAudioServiceInterface *mAAudioServiceInterface;
+ int mDeathCount;
+};
+
+FuzzAAudioClient::FuzzAAudioClient(sp<AAudioService> service) : AAudioServiceInterface() {
+ mAAudioService = service;
+ mAAudioServiceInterface = &service->asAAudioServiceInterface();
+ mAAudioClient = new AAudioClient(this);
+ mDeathCount = 0;
+ if (mAAudioClient.get() && mAAudioService.get()) {
+ mAAudioService->linkToDeath(mAAudioClient);
+ mAAudioService->registerClient(mAAudioClient);
+ }
+}
+
+FuzzAAudioClient::~FuzzAAudioClient() { dropAAudioService(); }
+
+AAudioServiceInterface *FuzzAAudioClient::getAAudioService() {
+ if (!mAAudioServiceInterface && mAAudioService.get()) {
+ mAAudioServiceInterface = &mAAudioService->asAAudioServiceInterface();
+ }
+ return mAAudioServiceInterface;
+}
+
+void FuzzAAudioClient::dropAAudioService() {
+ mAAudioService.clear();
+}
+
+aaudio_handle_t FuzzAAudioClient::openStream(const AAudioStreamRequest &request,
+ AAudioStreamConfiguration &configurationOutput) {
+ aaudio_handle_t stream;
+ for (int i = 0; i < 2; ++i) {
+ AAudioServiceInterface *service = getAAudioService();
+ if (!service) {
+ return AAUDIO_ERROR_NO_SERVICE;
+ }
+
+ stream = service->openStream(request, configurationOutput);
+
+ if (stream == AAUDIO_ERROR_NO_SERVICE) {
+ dropAAudioService();
+ } else {
+ break;
+ }
+ }
+ return stream;
+}
+
+aaudio_result_t FuzzAAudioClient::closeStream(aaudio_handle_t streamHandle) {
+ AAudioServiceInterface *service = getAAudioService();
+ if (!service) {
+ return AAUDIO_ERROR_NO_SERVICE;
+ }
+ return service->closeStream(streamHandle);
+}
+
+aaudio_result_t FuzzAAudioClient::getStreamDescription(aaudio_handle_t streamHandle,
+ AudioEndpointParcelable &parcelable) {
+ AAudioServiceInterface *service = getAAudioService();
+ if (!service) {
+ return AAUDIO_ERROR_NO_SERVICE;
+ }
+ return service->getStreamDescription(streamHandle, parcelable);
+}
+
+aaudio_result_t FuzzAAudioClient::startStream(aaudio_handle_t streamHandle) {
+ AAudioServiceInterface *service = getAAudioService();
+ if (!service) {
+ return AAUDIO_ERROR_NO_SERVICE;
+ }
+ return service->startStream(streamHandle);
+}
+
+aaudio_result_t FuzzAAudioClient::pauseStream(aaudio_handle_t streamHandle) {
+ AAudioServiceInterface *service = getAAudioService();
+ if (!service) {
+ return AAUDIO_ERROR_NO_SERVICE;
+ }
+ return service->pauseStream(streamHandle);
+}
+
+aaudio_result_t FuzzAAudioClient::stopStream(aaudio_handle_t streamHandle) {
+ AAudioServiceInterface *service = getAAudioService();
+ if (!service) {
+ return AAUDIO_ERROR_NO_SERVICE;
+ }
+ return service->stopStream(streamHandle);
+}
+
+aaudio_result_t FuzzAAudioClient::flushStream(aaudio_handle_t streamHandle) {
+ AAudioServiceInterface *service = getAAudioService();
+ if (!service) {
+ return AAUDIO_ERROR_NO_SERVICE;
+ }
+ return service->flushStream(streamHandle);
+}
+
+aaudio_result_t FuzzAAudioClient::registerAudioThread(aaudio_handle_t streamHandle,
+ pid_t clientThreadId,
+ int64_t periodNanoseconds) {
+ AAudioServiceInterface *service = getAAudioService();
+ if (!service) {
+ return AAUDIO_ERROR_NO_SERVICE;
+ }
+ return service->registerAudioThread(streamHandle, clientThreadId, periodNanoseconds);
+}
+
+aaudio_result_t FuzzAAudioClient::unregisterAudioThread(aaudio_handle_t streamHandle,
+ pid_t clientThreadId) {
+ AAudioServiceInterface *service = getAAudioService();
+ if (!service) {
+ return AAUDIO_ERROR_NO_SERVICE;
+ }
+ return service->unregisterAudioThread(streamHandle, clientThreadId);
+}
+
+class OboeserviceFuzzer {
+ public:
+ OboeserviceFuzzer();
+ ~OboeserviceFuzzer() = default;
+ void process(const uint8_t *data, size_t size);
+
+ private:
+ sp<FuzzAAudioClient> mClient;
+};
+
+OboeserviceFuzzer::OboeserviceFuzzer() {
+ sp<AAudioService> service = new AAudioService();
+ mClient = new FuzzAAudioClient(service);
+}
+
+void OboeserviceFuzzer::process(const uint8_t *data, size_t size) {
+ FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+ AAudioStreamRequest request;
+ AAudioStreamConfiguration configurationOutput;
+
+ // Initialize stream request
+ request.getConfiguration().setFormat((audio_format_t)(
+ fdp.ConsumeBool()
+ ? fdp.ConsumeIntegral<int32_t>()
+ : kAAudioFormats[fdp.ConsumeIntegralInRange<int32_t>(0, kNumAAudioFormats - 1)]));
+
+ // TODO b/182392769: use identity util
+ media::permission::Identity identity;
+ identity.uid = getuid();
+ identity.pid = getpid();
+ request.setIdentity(identity);
+ request.setInService(fdp.ConsumeBool());
+
+ request.getConfiguration().setDeviceId(fdp.ConsumeIntegral<int32_t>());
+ request.getConfiguration().setSampleRate(fdp.ConsumeIntegral<int32_t>());
+ request.getConfiguration().setSamplesPerFrame(fdp.ConsumeIntegral<int32_t>());
+ request.getConfiguration().setDirection(
+ fdp.ConsumeBool() ? fdp.ConsumeIntegral<int32_t>()
+ : (fdp.ConsumeBool() ? AAUDIO_DIRECTION_OUTPUT : AAUDIO_DIRECTION_INPUT));
+ request.getConfiguration().setSharingMode(
+ fdp.ConsumeBool()
+ ? fdp.ConsumeIntegral<int32_t>()
+ : (fdp.ConsumeBool() ? AAUDIO_SHARING_MODE_EXCLUSIVE : AAUDIO_SHARING_MODE_SHARED));
+
+ request.getConfiguration().setUsage(
+ fdp.ConsumeBool()
+ ? fdp.ConsumeIntegral<int32_t>()
+ : kAAudioUsages[fdp.ConsumeIntegralInRange<int32_t>(0, kNumAAudioUsages - 1)]);
+ request.getConfiguration().setContentType(
+ fdp.ConsumeBool() ? fdp.ConsumeIntegral<int32_t>()
+ : kAAudioContentTypes[fdp.ConsumeIntegralInRange<int32_t>(
+ 0, kNumAAudioContentTypes - 1)]);
+ request.getConfiguration().setInputPreset(
+ fdp.ConsumeBool() ? fdp.ConsumeIntegral<int32_t>()
+ : kAAudioInputPresets[fdp.ConsumeIntegralInRange<int32_t>(
+ 0, kNumAAudioInputPresets - 1)]);
+ request.getConfiguration().setPrivacySensitive(fdp.ConsumeBool());
+
+ request.getConfiguration().setBufferCapacity(fdp.ConsumeIntegral<int32_t>());
+
+ aaudio_handle_t stream = mClient->openStream(request, configurationOutput);
+ if (stream < 0) {
+ // invalid request, stream not opened.
+ return;
+ }
+ while (fdp.remaining_bytes()) {
+ AudioEndpointParcelable audioEndpointParcelable;
+ int action = fdp.ConsumeIntegralInRange<int32_t>(0, 4);
+ switch (action) {
+ case 0:
+ mClient->getStreamDescription(stream, audioEndpointParcelable);
+ break;
+ case 1:
+ mClient->startStream(stream);
+ break;
+ case 2:
+ mClient->pauseStream(stream);
+ break;
+ case 3:
+ mClient->stopStream(stream);
+ break;
+ case 4:
+ mClient->flushStream(stream);
+ break;
+ }
+ }
+ mClient->closeStream(stream);
+ assert(mClient->getDeathCount() == 0);
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ if (size < 1) {
+ return 0;
+ }
+ OboeserviceFuzzer oboeserviceFuzzer;
+ oboeserviceFuzzer.process(data, size);
+ return 0;
+}