Merge "HEIF decoder: support 10-bit color format"
diff --git a/Android.bp b/Android.bp
index 60f0ff1..ee609e1 100644
--- a/Android.bp
+++ b/Android.bp
@@ -57,7 +57,7 @@
min_sdk_version: "29",
apex_available: [
"//apex_available:platform",
- "com.android.bluetooth.updatable",
+ "com.android.bluetooth",
"com.android.media",
"com.android.media.swcodec",
],
@@ -86,7 +86,7 @@
min_sdk_version: "29",
apex_available: [
"//apex_available:platform",
- "com.android.bluetooth.updatable",
+ "com.android.bluetooth",
"com.android.media",
"com.android.media.swcodec",
],
diff --git a/OWNERS b/OWNERS
index 0be1196..40c65e7 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,7 +1,6 @@
# Bug component: 1344
elaurent@google.com
etalvala@google.com
-hkuang@google.com
lajos@google.com
# go/android-fwk-media-solutions for info on areas of ownership.
diff --git a/camera/Android.bp b/camera/Android.bp
index 4ed3269..e44202b 100644
--- a/camera/Android.bp
+++ b/camera/Android.bp
@@ -113,6 +113,30 @@
}
+cc_library_host_static {
+ name: "libcamera_client_host",
+
+ srcs: [
+ "CameraMetadata.cpp",
+ "VendorTagDescriptor.cpp",
+ ],
+
+ shared_libs: [
+ "libbase",
+ "libcamera_metadata",
+ ],
+
+ include_dirs: [
+ "system/media/private/camera/include",
+ "frameworks/native/include/media/openmax",
+ ],
+
+ export_include_dirs: [
+ "include",
+ "include/camera"
+ ],
+}
+
// AIDL interface between camera clients and the camera service.
filegroup {
name: "libcamera_client_aidl",
diff --git a/camera/CameraSessionStats.cpp b/camera/CameraSessionStats.cpp
index 28e037f..bc83ec1 100644
--- a/camera/CameraSessionStats.cpp
+++ b/camera/CameraSessionStats.cpp
@@ -112,6 +112,12 @@
return err;
}
+ int dynamicRangeProfile = ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD;
+ if ((err = parcel->readInt32(&dynamicRangeProfile)) != OK) {
+ ALOGE("%s: Failed to read dynamic range profile type from parcel", __FUNCTION__);
+ return err;
+ }
+
mWidth = width;
mHeight = height;
mFormat = format;
@@ -125,6 +131,7 @@
mHistogramType = histogramType;
mHistogramBins = std::move(histogramBins);
mHistogramCounts = std::move(histogramCounts);
+ mDynamicRangeProfile = dynamicRangeProfile;
return OK;
}
@@ -202,6 +209,11 @@
return err;
}
+ if ((err = parcel->writeInt32(mDynamicRangeProfile)) != OK) {
+ ALOGE("%s: Failed to write dynamic range profile type", __FUNCTION__);
+ return err;
+ }
+
return OK;
}
diff --git a/camera/aidl/android/hardware/ICameraService.aidl b/camera/aidl/android/hardware/ICameraService.aidl
index 78a77d4..1e748c7 100644
--- a/camera/aidl/android/hardware/ICameraService.aidl
+++ b/camera/aidl/android/hardware/ICameraService.aidl
@@ -173,6 +173,13 @@
void setTorchMode(String cameraId, boolean enabled, IBinder clientBinder);
+ // Change the brightness level of the flash unit associated with cameraId to strengthLevel.
+ // If the torch is in OFF state and strengthLevel > 0 then the torch will also be turned ON.
+ void turnOnTorchWithStrengthLevel(String cameraId, int strengthLevel, IBinder clientBinder);
+
+ // Get the brightness level of the flash unit associated with cameraId.
+ int getTorchStrengthLevel(String cameraId);
+
/**
* Notify the camera service of a system event. Should only be called from system_server.
*
@@ -180,6 +187,8 @@
*/
const int EVENT_NONE = 0;
const int EVENT_USER_SWITCHED = 1; // The argument is the set of new foreground user IDs.
+ const int EVENT_USB_DEVICE_ATTACHED = 2; // The argument is the deviceId and vendorId
+ const int EVENT_USB_DEVICE_DETACHED = 3; // The argument is the deviceId and vendorId
oneway void notifySystemEvent(int eventId, in int[] args);
/**
diff --git a/camera/aidl/android/hardware/ICameraServiceListener.aidl b/camera/aidl/android/hardware/ICameraServiceListener.aidl
index c54813c..5f17f5b 100644
--- a/camera/aidl/android/hardware/ICameraServiceListener.aidl
+++ b/camera/aidl/android/hardware/ICameraServiceListener.aidl
@@ -83,6 +83,8 @@
oneway void onTorchStatusChanged(int status, String cameraId);
+ oneway void onTorchStrengthLevelChanged(String cameraId, int newTorchStrength);
+
/**
* Notify registered clients about camera access priority changes.
* Clients which were previously unable to open a certain camera device
diff --git a/camera/aidl/android/hardware/ICameraServiceProxy.aidl b/camera/aidl/android/hardware/ICameraServiceProxy.aidl
index 3d78aef..f5d0120 100644
--- a/camera/aidl/android/hardware/ICameraServiceProxy.aidl
+++ b/camera/aidl/android/hardware/ICameraServiceProxy.aidl
@@ -43,5 +43,5 @@
* {@link android.hardware.camera2.CameraMetadata#SCALER_ROTATE_AND_CROP_180},
* {@link android.hardware.camera2.CameraMetadata#SCALER_ROTATE_AND_CROP_270}).
*/
- int getRotateAndCropOverride(String packageName, int lensFacing);
+ int getRotateAndCropOverride(String packageName, int lensFacing, int userId);
}
diff --git a/camera/camera2/OutputConfiguration.cpp b/camera/camera2/OutputConfiguration.cpp
index 2bccd87..15c9dc9 100644
--- a/camera/camera2/OutputConfiguration.cpp
+++ b/camera/camera2/OutputConfiguration.cpp
@@ -23,6 +23,7 @@
#include <camera/camera2/OutputConfiguration.h>
#include <binder/Parcel.h>
#include <gui/view/Surface.h>
+#include <system/camera_metadata.h>
#include <utils/String8.h>
namespace android {
@@ -76,6 +77,10 @@
return mSensorPixelModesUsed;
}
+int OutputConfiguration::getDynamicRangeProfile() const {
+ return mDynamicRangeProfile;
+}
+
OutputConfiguration::OutputConfiguration() :
mRotation(INVALID_ROTATION),
mSurfaceSetID(INVALID_SET_ID),
@@ -84,7 +89,8 @@
mHeight(0),
mIsDeferred(false),
mIsShared(false),
- mIsMultiResolution(false) {
+ mIsMultiResolution(false),
+ mDynamicRangeProfile(ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD) {
}
OutputConfiguration::OutputConfiguration(const android::Parcel& parcel) :
@@ -165,6 +171,12 @@
ALOGE("%s: Failed to read sensor pixel mode(s) from parcel", __FUNCTION__);
return err;
}
+ int dynamicProfile;
+ if ((err = parcel->readInt32(&dynamicProfile)) != OK) {
+ ALOGE("%s: Failed to read surface dynamic range profile flag from parcel", __FUNCTION__);
+ return err;
+ }
+
mRotation = rotation;
mSurfaceSetID = setID;
mSurfaceType = surfaceType;
@@ -181,6 +193,7 @@
}
mSensorPixelModesUsed = std::move(sensorPixelModesUsed);
+ mDynamicRangeProfile = dynamicProfile;
ALOGV("%s: OutputConfiguration: rotation = %d, setId = %d, surfaceType = %d,"
" physicalCameraId = %s, isMultiResolution = %d", __FUNCTION__, mRotation,
@@ -199,6 +212,7 @@
mIsShared = isShared;
mPhysicalCameraId = physicalId;
mIsMultiResolution = false;
+ mDynamicRangeProfile = ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD;
}
OutputConfiguration::OutputConfiguration(
@@ -207,7 +221,8 @@
int width, int height, bool isShared)
: mGbps(gbps), mRotation(rotation), mSurfaceSetID(surfaceSetID), mSurfaceType(surfaceType),
mWidth(width), mHeight(height), mIsDeferred(false), mIsShared(isShared),
- mPhysicalCameraId(physicalCameraId), mIsMultiResolution(false) { }
+ mPhysicalCameraId(physicalCameraId), mIsMultiResolution(false),
+ mDynamicRangeProfile(ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD) { }
status_t OutputConfiguration::writeToParcel(android::Parcel* parcel) const {
@@ -254,6 +269,9 @@
err = parcel->writeParcelableVector(mSensorPixelModesUsed);
if (err != OK) return err;
+ err = parcel->writeInt32(mDynamicRangeProfile ? 1 : 0);
+ if (err != OK) return err;
+
return OK;
}
diff --git a/camera/cameraserver/Android.bp b/camera/cameraserver/Android.bp
index 8ca8920..6d884cb 100644
--- a/camera/cameraserver/Android.bp
+++ b/camera/cameraserver/Android.bp
@@ -46,6 +46,7 @@
"android.hardware.camera.device@1.0",
"android.hardware.camera.device@3.2",
"android.hardware.camera.device@3.4",
+ "android.hardware.camera.device@3.8",
],
compile_multilib: "first",
cflags: [
diff --git a/camera/include/camera/CameraSessionStats.h b/camera/include/camera/CameraSessionStats.h
index c398aca..1209a20 100644
--- a/camera/include/camera/CameraSessionStats.h
+++ b/camera/include/camera/CameraSessionStats.h
@@ -19,6 +19,8 @@
#include <binder/Parcelable.h>
+#include <camera/CameraMetadata.h>
+
namespace android {
namespace hardware {
@@ -60,16 +62,21 @@
// size(mHistogramBins) + 1 = size(mHistogramCounts)
std::vector<int64_t> mHistogramCounts;
+ // Dynamic range profile
+ int mDynamicRangeProfile;
+
CameraStreamStats() :
mWidth(0), mHeight(0), mFormat(0), mDataSpace(0), mUsage(0),
mRequestCount(0), mErrorCount(0), mStartLatencyMs(0),
- mMaxHalBuffers(0), mMaxAppBuffers(0), mHistogramType(HISTOGRAM_TYPE_UNKNOWN) {}
+ mMaxHalBuffers(0), mMaxAppBuffers(0), mHistogramType(HISTOGRAM_TYPE_UNKNOWN),
+ mDynamicRangeProfile(ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD) {}
CameraStreamStats(int width, int height, int format, int dataSpace, int64_t usage,
- int maxHalBuffers, int maxAppBuffers)
+ int maxHalBuffers, int maxAppBuffers, int dynamicRangeProfile)
: mWidth(width), mHeight(height), mFormat(format), mDataSpace(dataSpace),
mUsage(usage), mRequestCount(0), mErrorCount(0), mStartLatencyMs(0),
mMaxHalBuffers(maxHalBuffers), mMaxAppBuffers(maxAppBuffers),
- mHistogramType(HISTOGRAM_TYPE_UNKNOWN) {}
+ mHistogramType(HISTOGRAM_TYPE_UNKNOWN),
+ mDynamicRangeProfile(dynamicRangeProfile) {}
virtual status_t readFromParcel(const android::Parcel* parcel) override;
virtual status_t writeToParcel(android::Parcel* parcel) const override;
diff --git a/camera/include/camera/camera2/OutputConfiguration.h b/camera/include/camera/camera2/OutputConfiguration.h
index f80ed3a..1631903 100644
--- a/camera/include/camera/camera2/OutputConfiguration.h
+++ b/camera/include/camera/camera2/OutputConfiguration.h
@@ -44,6 +44,7 @@
int getSurfaceType() const;
int getWidth() const;
int getHeight() const;
+ int getDynamicRangeProfile() const;
bool isDeferred() const;
bool isShared() const;
String16 getPhysicalCameraId() const;
@@ -89,7 +90,8 @@
gbpsEqual(other) &&
mPhysicalCameraId == other.mPhysicalCameraId &&
mIsMultiResolution == other.mIsMultiResolution &&
- sensorPixelModesUsedEqual(other));
+ sensorPixelModesUsedEqual(other) &&
+ mDynamicRangeProfile == other.mDynamicRangeProfile);
}
bool operator != (const OutputConfiguration& other) const {
return !(*this == other);
@@ -126,6 +128,9 @@
if (!sensorPixelModesUsedEqual(other)) {
return sensorPixelModesUsedLessThan(other);
}
+ if (mDynamicRangeProfile != other.mDynamicRangeProfile) {
+ return mDynamicRangeProfile < other.mDynamicRangeProfile;
+ }
return gbpsLessThan(other);
}
@@ -150,6 +155,7 @@
String16 mPhysicalCameraId;
bool mIsMultiResolution;
std::vector<int32_t> mSensorPixelModesUsed;
+ int mDynamicRangeProfile;
};
} // namespace params
} // namespace camera2
diff --git a/camera/ndk/NdkCameraCaptureSession.cpp b/camera/ndk/NdkCameraCaptureSession.cpp
index 1ac8482..9c98778 100644
--- a/camera/ndk/NdkCameraCaptureSession.cpp
+++ b/camera/ndk/NdkCameraCaptureSession.cpp
@@ -29,6 +29,7 @@
#include "impl/ACameraCaptureSession.h"
#include "impl/ACameraCaptureSession.inc"
+#include "NdkCameraCaptureSession.inc"
using namespace android;
@@ -72,22 +73,16 @@
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId) {
ATRACE_CALL();
- if (session == nullptr || requests == nullptr || numRequests < 1) {
- ALOGE("%s: Error: invalid input: session %p, numRequest %d, requests %p",
- __FUNCTION__, session, numRequests, requests);
- return ACAMERA_ERROR_INVALID_PARAMETER;
- }
+ return captureTemplate(session, cbs, numRequests, requests, captureSequenceId);
+}
- if (session->isClosed()) {
- ALOGE("%s: session %p is already closed", __FUNCTION__, session);
- if (captureSequenceId != nullptr) {
- *captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
- }
- return ACAMERA_ERROR_SESSION_CLOSED;
- }
-
- return session->capture(
- cbs, numRequests, requests, captureSequenceId);
+EXPORT
+camera_status_t ACameraCaptureSession_captureV2(
+ ACameraCaptureSession* session, /*optional*/ACameraCaptureSession_captureCallbacksV2* cbs,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId) {
+ ATRACE_CALL();
+ return captureTemplate(session, cbs, numRequests, requests, captureSequenceId);
}
EXPORT
@@ -97,22 +92,26 @@
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId) {
ATRACE_CALL();
- if (session == nullptr || requests == nullptr || numRequests < 1) {
- ALOGE("%s: Error: invalid input: session %p, numRequest %d, requests %p",
- __FUNCTION__, session, numRequests, requests);
- return ACAMERA_ERROR_INVALID_PARAMETER;
- }
+ return captureTemplate(session, lcbs, numRequests, requests, captureSequenceId);
+}
- if (session->isClosed()) {
- ALOGE("%s: session %p is already closed", __FUNCTION__, session);
- if (captureSequenceId) {
- *captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
- }
- return ACAMERA_ERROR_SESSION_CLOSED;
- }
+EXPORT
+camera_status_t ACameraCaptureSession_logicalCamera_captureV2(
+ ACameraCaptureSession* session,
+ /*optional*/ACameraCaptureSession_logicalCamera_captureCallbacksV2* lcbs,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId) {
+ ATRACE_CALL();
+ return captureTemplate(session, lcbs, numRequests, requests, captureSequenceId);
+}
- return session->capture(
- lcbs, numRequests, requests, captureSequenceId);
+EXPORT
+camera_status_t ACameraCaptureSession_setRepeatingRequestV2(
+ ACameraCaptureSession* session, /*optional*/ACameraCaptureSession_captureCallbacksV2* cbs,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId) {
+ ATRACE_CALL();
+ return setRepeatingRequestTemplate(session, cbs, numRequests, requests, captureSequenceId);
}
EXPORT
@@ -121,23 +120,10 @@
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId) {
ATRACE_CALL();
- if (session == nullptr || requests == nullptr || numRequests < 1) {
- ALOGE("%s: Error: invalid input: session %p, numRequest %d, requests %p",
- __FUNCTION__, session, numRequests, requests);
- return ACAMERA_ERROR_INVALID_PARAMETER;
- }
-
- if (session->isClosed()) {
- ALOGE("%s: session %p is already closed", __FUNCTION__, session);
- if (captureSequenceId) {
- *captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
- }
- return ACAMERA_ERROR_SESSION_CLOSED;
- }
-
- return session->setRepeatingRequest(cbs, numRequests, requests, captureSequenceId);
+ return setRepeatingRequestTemplate(session, cbs, numRequests, requests, captureSequenceId);
}
+
EXPORT
camera_status_t ACameraCaptureSession_logicalCamera_setRepeatingRequest(
ACameraCaptureSession* session,
@@ -145,21 +131,18 @@
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId) {
ATRACE_CALL();
- if (session == nullptr || requests == nullptr || numRequests < 1) {
- ALOGE("%s: Error: invalid input: session %p, numRequest %d, requests %p",
- __FUNCTION__, session, numRequests, requests);
- return ACAMERA_ERROR_INVALID_PARAMETER;
- }
+ return setRepeatingRequestTemplate(session, lcbs, numRequests, requests, captureSequenceId);
+}
- if (session->isClosed()) {
- ALOGE("%s: session %p is already closed", __FUNCTION__, session);
- if (captureSequenceId) {
- *captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
- }
- return ACAMERA_ERROR_SESSION_CLOSED;
- }
- return session->setRepeatingRequest(lcbs, numRequests, requests, captureSequenceId);
+EXPORT
+camera_status_t ACameraCaptureSession_logicalCamera_setRepeatingRequestV2(
+ ACameraCaptureSession* session,
+ /*optional*/ACameraCaptureSession_logicalCamera_captureCallbacksV2* lcbs,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId) {
+ ATRACE_CALL();
+ return setRepeatingRequestTemplate(session, lcbs, numRequests, requests, captureSequenceId);
}
EXPORT
diff --git a/camera/ndk/NdkCameraCaptureSession.inc b/camera/ndk/NdkCameraCaptureSession.inc
new file mode 100644
index 0000000..258e20d
--- /dev/null
+++ b/camera/ndk/NdkCameraCaptureSession.inc
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2022 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 "impl/ACameraCaptureSession.h"
+
+#include <camera/NdkCameraCaptureSession.h>
+
+using namespace android;
+
+template <class CallbackType>
+camera_status_t captureTemplate(
+ ACameraCaptureSession* session,
+ /*optional*/CallbackType* cbs,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId) {
+ ATRACE_CALL();
+ if (session == nullptr || requests == nullptr || numRequests < 1) {
+ ALOGE("%s: Error: invalid input: session %p, numRequest %d, requests %p",
+ __FUNCTION__, session, numRequests, requests);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+
+ if (session->isClosed()) {
+ ALOGE("%s: session %p is already closed", __FUNCTION__, session);
+ if (captureSequenceId) {
+ *captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
+ }
+ return ACAMERA_ERROR_SESSION_CLOSED;
+ }
+
+ return session->capture(
+ cbs, numRequests, requests, captureSequenceId);
+}
+
+template <class CallbackType>
+camera_status_t setRepeatingRequestTemplate(
+ ACameraCaptureSession* session,
+ /*optional*/CallbackType* cbs,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId) {
+ ATRACE_CALL();
+ if (session == nullptr || requests == nullptr || numRequests < 1) {
+ ALOGE("%s: Error: invalid input: session %p, numRequest %d, requests %p",
+ __FUNCTION__, session, numRequests, requests);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+
+ if (session->isClosed()) {
+ ALOGE("%s: session %p is already closed", __FUNCTION__, session);
+ if (captureSequenceId) {
+ *captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
+ }
+ return ACAMERA_ERROR_SESSION_CLOSED;
+ }
+
+ return session->setRepeatingRequest(cbs, numRequests, requests, captureSequenceId);
+}
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index dd652c7..7997768 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -26,8 +26,6 @@
#include "ACaptureRequest.h"
#include "ACameraCaptureSession.h"
-#include "ACameraCaptureSession.inc"
-
ACameraDevice::~ACameraDevice() {
mDevice->stopLooperAndDisconnect();
}
@@ -913,6 +911,7 @@
case kWhatOnError:
case kWhatSessionStateCb:
case kWhatCaptureStart:
+ case kWhatCaptureStart2:
case kWhatCaptureResult:
case kWhatLogicalCaptureResult:
case kWhatCaptureFail:
@@ -985,6 +984,7 @@
}
case kWhatSessionStateCb:
case kWhatCaptureStart:
+ case kWhatCaptureStart2:
case kWhatCaptureResult:
case kWhatLogicalCaptureResult:
case kWhatCaptureFail:
@@ -1004,6 +1004,7 @@
sp<CaptureRequest> requestSp = nullptr;
switch (msg->what()) {
case kWhatCaptureStart:
+ case kWhatCaptureStart2:
case kWhatCaptureResult:
case kWhatLogicalCaptureResult:
case kWhatCaptureFail:
@@ -1055,6 +1056,35 @@
freeACaptureRequest(request);
break;
}
+ case kWhatCaptureStart2:
+ {
+ ACameraCaptureSession_captureCallback_startV2 onStart2;
+ found = msg->findPointer(kCallbackFpKey, (void**) &onStart2);
+ if (!found) {
+ ALOGE("%s: Cannot find capture startV2 callback!", __FUNCTION__);
+ return;
+ }
+ if (onStart2 == nullptr) {
+ return;
+ }
+ int64_t timestamp;
+ found = msg->findInt64(kTimeStampKey, ×tamp);
+ if (!found) {
+ ALOGE("%s: Cannot find timestamp!", __FUNCTION__);
+ return;
+ }
+ int64_t frameNumber;
+ found = msg->findInt64(kFrameNumberKey, &frameNumber);
+ if (!found) {
+ ALOGE("%s: Cannot find frame number!", __FUNCTION__);
+ return;
+ }
+
+ ACaptureRequest* request = allocateACaptureRequest(requestSp, mId);
+ (*onStart2)(context, session.get(), request, timestamp, frameNumber);
+ freeACaptureRequest(request);
+ break;
+ }
case kWhatCaptureResult:
{
ACameraCaptureSession_captureCallback_result onResult;
@@ -1285,7 +1315,8 @@
ACameraCaptureSession_captureCallbacks* cbs) :
mSession(session), mRequests(requests),
mIsRepeating(isRepeating),
- mIsLogicalCameraCallback(false) {
+ mIsLogicalCameraCallback(false),
+ mIs2Callback(false) {
initCaptureCallbacks(cbs);
if (cbs != nullptr) {
@@ -1301,7 +1332,8 @@
ACameraCaptureSession_logicalCamera_captureCallbacks* lcbs) :
mSession(session), mRequests(requests),
mIsRepeating(isRepeating),
- mIsLogicalCameraCallback(true) {
+ mIsLogicalCameraCallback(true),
+ mIs2Callback(false) {
initCaptureCallbacks(lcbs);
if (lcbs != nullptr) {
@@ -1310,6 +1342,40 @@
}
}
+CameraDevice::CallbackHolder::CallbackHolder(
+ sp<ACameraCaptureSession> session,
+ const Vector<sp<CaptureRequest> >& requests,
+ bool isRepeating,
+ ACameraCaptureSession_captureCallbacksV2* cbs) :
+ mSession(session), mRequests(requests),
+ mIsRepeating(isRepeating),
+ mIsLogicalCameraCallback(false),
+ mIs2Callback(true) {
+ initCaptureCallbacksV2(cbs);
+
+ if (cbs != nullptr) {
+ mOnCaptureCompleted = cbs->onCaptureCompleted;
+ mOnCaptureFailed = cbs->onCaptureFailed;
+ }
+}
+
+CameraDevice::CallbackHolder::CallbackHolder(
+ sp<ACameraCaptureSession> session,
+ const Vector<sp<CaptureRequest> >& requests,
+ bool isRepeating,
+ ACameraCaptureSession_logicalCamera_captureCallbacksV2* lcbs) :
+ mSession(session), mRequests(requests),
+ mIsRepeating(isRepeating),
+ mIsLogicalCameraCallback(true),
+ mIs2Callback(true) {
+ initCaptureCallbacksV2(lcbs);
+
+ if (lcbs != nullptr) {
+ mOnLogicalCameraCaptureCompleted = lcbs->onLogicalCameraCaptureCompleted;
+ mOnLogicalCameraCaptureFailed = lcbs->onLogicalCameraCaptureFailed;
+ }
+}
+
void
CameraDevice::checkRepeatingSequenceCompleteLocked(
const int sequenceId, const int64_t lastFrameNumber) {
@@ -1536,7 +1602,6 @@
const CaptureResultExtras& resultExtras,
int64_t timestamp) {
binder::Status ret = binder::Status::ok();
-
sp<CameraDevice> dev = mDevice.promote();
if (dev == nullptr) {
return ret; // device has been closed
@@ -1551,11 +1616,14 @@
int sequenceId = resultExtras.requestId;
int32_t burstId = resultExtras.burstId;
+ int64_t frameNumber = resultExtras.frameNumber;
auto it = dev->mSequenceCallbackMap.find(sequenceId);
if (it != dev->mSequenceCallbackMap.end()) {
CallbackHolder cbh = (*it).second;
+ bool v2Callback = cbh.mIs2Callback;
ACameraCaptureSession_captureCallback_start onStart = cbh.mOnCaptureStarted;
+ ACameraCaptureSession_captureCallback_startV2 onStart2 = cbh.mOnCaptureStarted2;
sp<ACameraCaptureSession> session = cbh.mSession;
if ((size_t) burstId >= cbh.mRequests.size()) {
ALOGE("%s: Error: request index %d out of bound (size %zu)",
@@ -1563,12 +1631,19 @@
dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
}
sp<CaptureRequest> request = cbh.mRequests[burstId];
- sp<AMessage> msg = new AMessage(kWhatCaptureStart, dev->mHandler);
+ sp<AMessage> msg = nullptr;
+ if (v2Callback) {
+ msg = new AMessage(kWhatCaptureStart2, dev->mHandler);
+ msg->setPointer(kCallbackFpKey, (void*) onStart2);
+ } else {
+ msg = new AMessage(kWhatCaptureStart, dev->mHandler);
+ msg->setPointer(kCallbackFpKey, (void *)onStart);
+ }
msg->setPointer(kContextKey, cbh.mContext);
msg->setObject(kSessionSpKey, session);
- msg->setPointer(kCallbackFpKey, (void*) onStart);
msg->setObject(kCaptureRequestKey, request);
msg->setInt64(kTimeStampKey, timestamp);
+ msg->setInt64(kFrameNumberKey, frameNumber);
dev->postSessionMsgAndCleanup(msg);
}
return ret;
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h
index 344d964..17988fe 100644
--- a/camera/ndk/impl/ACameraDevice.h
+++ b/camera/ndk/impl/ACameraDevice.h
@@ -215,6 +215,7 @@
kWhatSessionStateCb, // onReady, onActive
// Capture callbacks
kWhatCaptureStart, // onCaptureStarted
+ kWhatCaptureStart2, // onCaptureStarted
kWhatCaptureResult, // onCaptureProgressed, onCaptureCompleted
kWhatLogicalCaptureResult, // onLogicalCameraCaptureCompleted
kWhatCaptureFail, // onCaptureFailed
@@ -294,11 +295,18 @@
const Vector<sp<CaptureRequest> >& requests,
bool isRepeating,
ACameraCaptureSession_logicalCamera_captureCallbacks* lcbs);
-
- template <class T>
- void initCaptureCallbacks(T* cbs) {
+ CallbackHolder(sp<ACameraCaptureSession> session,
+ const Vector<sp<CaptureRequest> >& requests,
+ bool isRepeating,
+ ACameraCaptureSession_captureCallbacksV2* cbs);
+ CallbackHolder(sp<ACameraCaptureSession> session,
+ const Vector<sp<CaptureRequest> >& requests,
+ bool isRepeating,
+ ACameraCaptureSession_logicalCamera_captureCallbacksV2* lcbs);
+ void clearCallbacks() {
mContext = nullptr;
mOnCaptureStarted = nullptr;
+ mOnCaptureStarted2 = nullptr;
mOnCaptureProgressed = nullptr;
mOnCaptureCompleted = nullptr;
mOnLogicalCameraCaptureCompleted = nullptr;
@@ -307,6 +315,24 @@
mOnCaptureSequenceCompleted = nullptr;
mOnCaptureSequenceAborted = nullptr;
mOnCaptureBufferLost = nullptr;
+ }
+
+ template <class T>
+ void initCaptureCallbacksV2(T* cbs) {
+ clearCallbacks();
+ if (cbs != nullptr) {
+ mContext = cbs->context;
+ mOnCaptureStarted2 = cbs->onCaptureStarted;
+ mOnCaptureProgressed = cbs->onCaptureProgressed;
+ mOnCaptureSequenceCompleted = cbs->onCaptureSequenceCompleted;
+ mOnCaptureSequenceAborted = cbs->onCaptureSequenceAborted;
+ mOnCaptureBufferLost = cbs->onCaptureBufferLost;
+ }
+ }
+
+ template <class T>
+ void initCaptureCallbacks(T* cbs) {
+ clearCallbacks();
if (cbs != nullptr) {
mContext = cbs->context;
mOnCaptureStarted = cbs->onCaptureStarted;
@@ -320,9 +346,11 @@
Vector<sp<CaptureRequest> > mRequests;
const bool mIsRepeating;
const bool mIsLogicalCameraCallback;
+ const bool mIs2Callback;
void* mContext;
ACameraCaptureSession_captureCallback_start mOnCaptureStarted;
+ ACameraCaptureSession_captureCallback_startV2 mOnCaptureStarted2;
ACameraCaptureSession_captureCallback_result mOnCaptureProgressed;
ACameraCaptureSession_captureCallback_result mOnCaptureCompleted;
ACameraCaptureSession_logicalCamera_captureCallback_result mOnLogicalCameraCaptureCompleted;
diff --git a/camera/ndk/impl/ACameraManager.h b/camera/ndk/impl/ACameraManager.h
index da887a2..d53d809 100644
--- a/camera/ndk/impl/ACameraManager.h
+++ b/camera/ndk/impl/ACameraManager.h
@@ -95,6 +95,9 @@
virtual binder::Status onTorchStatusChanged(int32_t, const String16&) {
return binder::Status::ok();
}
+ virtual binder::Status onTorchStrengthLevelChanged(const String16&, int32_t) {
+ return binder::Status::ok();
+ }
virtual binder::Status onCameraAccessPrioritiesChanged();
virtual binder::Status onCameraOpened(const String16&, const String16&) {
diff --git a/camera/ndk/include/camera/NdkCameraCaptureSession.h b/camera/ndk/include/camera/NdkCameraCaptureSession.h
index 2b7f040..b0fd00c 100644
--- a/camera/ndk/include/camera/NdkCameraCaptureSession.h
+++ b/camera/ndk/include/camera/NdkCameraCaptureSession.h
@@ -811,6 +811,184 @@
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId) __INTRODUCED_IN(29);
+/**
+ * The definition of camera capture start callback. The same as
+ * {@link ACameraCaptureSession_captureCallbacks#onCaptureStarted}, except that
+ * it has the frame number of the capture as well.
+ *
+ * @param context The optional application context provided by user in
+ * {@link ACameraCaptureSession_captureCallbacks}.
+ * @param session The camera capture session of interest.
+ * @param request The capture request that is starting. Note that this pointer points to a copy of
+ * capture request sent by application, so the address is different to what
+ * application sent but the content will match. This request will be freed by
+ * framework immediately after this callback returns.
+ * @param timestamp The timestamp when the capture is started. This timestamp will match
+ * {@link ACAMERA_SENSOR_TIMESTAMP} of the {@link ACameraMetadata} in
+ * {@link ACameraCaptureSession_captureCallbacks#onCaptureCompleted} callback.
+ * @param frameNumber the frame number of the capture started
+ */
+typedef void (*ACameraCaptureSession_captureCallback_startV2)(
+ void* context, ACameraCaptureSession* session,
+ const ACaptureRequest* request, int64_t timestamp, int64_t frameNumber);
+/**
+ * This has the same functionality as ACameraCaptureSession_captureCallbacks,
+ * with the exception that captureCallback_startV2 callback is
+ * used, instead of captureCallback_start, to support retrieving the frame number.
+ */
+typedef struct ACameraCaptureSession_captureCallbacksV2 {
+ /**
+ * Same as ACameraCaptureSession_captureCallbacks
+ */
+ void* context;
+
+ /**
+ * Same as {@link ACameraCaptureSession_captureCallbacks#onCaptureStarted},
+ * except that it has the frame number of the capture added in the parameter
+ * list.
+ */
+ ACameraCaptureSession_captureCallback_startV2 onCaptureStarted;
+
+ /**
+ * Same as {@link ACameraCaptureSession_captureCallbacks#onCaptureProgressed}.
+ */
+ ACameraCaptureSession_captureCallback_result onCaptureProgressed;
+
+ /**
+ * Same as {@link ACameraCaptureSession_captureCallbacks#onCaptureCompleted}.
+ */
+ ACameraCaptureSession_captureCallback_result onCaptureCompleted;
+
+ /**
+ * Same as {@link ACameraCaptureSession_captureCallbacks#onCaptureFailed}.
+ */
+ ACameraCaptureSession_captureCallback_failed onCaptureFailed;
+
+ /**
+ * Same as {@link ACameraCaptureSession_captureCallbacks#onCaptureSequenceCompleted}.
+ */
+ ACameraCaptureSession_captureCallback_sequenceEnd onCaptureSequenceCompleted;
+
+ /**
+ * Same as {@link ACameraCaptureSession_captureCallbacks#onCaptureSequenceAborted}.
+ */
+ ACameraCaptureSession_captureCallback_sequenceAbort onCaptureSequenceAborted;
+
+ /**
+ * Same as {@link ACameraCaptureSession_captureCallbacks#onCaptureBufferLost}.
+ */
+ ACameraCaptureSession_captureCallback_bufferLost onCaptureBufferLost;
+
+
+} ACameraCaptureSession_captureCallbacksV2;
+
+/**
+ * This has the same functionality as ACameraCaptureSession_logicalCamera_captureCallbacks,
+ * with the exception that an captureCallback_startV2 callback is
+ * used, instead of captureCallback_start, to support retrieving frame number.
+ */
+typedef struct ACameraCaptureSession_logicalCamera_captureCallbacksV2 {
+ /**
+ * Same as ACameraCaptureSession_captureCallbacks
+ */
+ void* context;
+
+ /**
+ * Same as {@link ACameraCaptureSession_captureCallbacks#onCaptureStarted},
+ * except that it has the frame number of the capture added in the parameter
+ * list.
+ */
+ ACameraCaptureSession_captureCallback_startV2 onCaptureStarted;
+
+
+ /**
+ * Same as {@link ACameraCaptureSession_captureCallbacks#onCaptureProgressed}.
+ */
+ ACameraCaptureSession_captureCallback_result onCaptureProgressed;
+
+ /**
+ * Same as
+ * {@link ACameraCaptureSession_logicalCamera_captureCallbacks#onLogicalCaptureCompleted}.
+ */
+ ACameraCaptureSession_logicalCamera_captureCallback_result onLogicalCameraCaptureCompleted;
+
+ /**
+ * This callback is called instead of {@link onLogicalCameraCaptureCompleted} when the
+ * camera device failed to produce a capture result for the
+ * request.
+ *
+ * <p>Other requests are unaffected, and some or all image buffers from
+ * the capture may have been pushed to their respective output
+ * streams.</p>
+ *
+ * <p>Note that the ACaptureRequest pointer in the callback will not match what application has
+ * submitted, but the contents the ACaptureRequest will match what application submitted.</p>
+ *
+ * @see ALogicalCameraCaptureFailure
+ */
+ ACameraCaptureSession_logicalCamera_captureCallback_failed onLogicalCameraCaptureFailed;
+
+ /**
+ * Same as {@link ACameraCaptureSession_captureCallbacks#onCaptureSequenceCompleted}.
+ */
+ ACameraCaptureSession_captureCallback_sequenceEnd onCaptureSequenceCompleted;
+
+ /**
+ * Same as {@link ACameraCaptureSession_captureCallbacks#onCaptureSequenceAborted}.
+ */
+ ACameraCaptureSession_captureCallback_sequenceAbort onCaptureSequenceAborted;
+
+ /**
+ * Same as {@link ACameraCaptureSession_captureCallbacks#onCaptureBufferLost}.
+ */
+ ACameraCaptureSession_captureCallback_bufferLost onCaptureBufferLost;
+
+} ACameraCaptureSession_logicalCamera_captureCallbacksV2;
+
+/**
+ * This has the same functionality as ACameraCaptureSession_capture, with added
+ * support for v2 of camera callbacks, where the onCaptureStarted callback
+ * adds frame number in its parameter list.
+ */
+camera_status_t ACameraCaptureSession_captureV2(
+ ACameraCaptureSession* session,
+ /*optional*/ACameraCaptureSession_captureCallbacksV2* callbacks,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId) __INTRODUCED_IN(33);
+
+/**
+ * This has the same functionality as ACameraCaptureSession_logical_setRepeatingRequest, with added
+ * support for v2 of logical multi-camera callbacks where the onCaptureStarted
+ * callback adds frame number in its parameter list.
+ */
+camera_status_t ACameraCaptureSession_setRepeatingRequestV2(
+ ACameraCaptureSession* session,
+ /*optional*/ACameraCaptureSession_captureCallbacksV2* callbacks,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId) __INTRODUCED_IN(33);
+
+/**
+ * This has the same functionality as ACameraCaptureSession_logical_capture, with added
+ * support for v2 of logical multi-camera callbacks where the onCaptureStarted callback
+ * adds frame number in its parameter list.
+ */
+camera_status_t ACameraCaptureSession_logicalCamera_captureV2(
+ ACameraCaptureSession* session,
+ /*optional*/ACameraCaptureSession_logicalCamera_captureCallbacksV2* callbacks,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId) __INTRODUCED_IN(33);
+
+/**
+ * This has the same functionality as ACameraCaptureSession_logical_setRepeatingRequest, with added
+ * support for v2 of logical multi-camera callbacks where the onCaptureStarted
+ * callback adds frame number in its parameter list.
+ */
+camera_status_t ACameraCaptureSession_logicalCamera_setRepeatingRequestV2(
+ ACameraCaptureSession* session,
+ /*optional*/ACameraCaptureSession_logicalCamera_captureCallbacksV2* callbacks,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId) __INTRODUCED_IN(33);
+
__END_DECLS
#endif /* _NDK_CAMERA_CAPTURE_SESSION_H */
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 0e9740a..bd281c8 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -3463,6 +3463,25 @@
*/
ACAMERA_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS = // int32[n]
ACAMERA_REQUEST_START + 17,
+ /**
+ * <p>A map of all available 10-bit dynamic range profiles along with their
+ * capture request constraints.</p>
+ *
+ * <p>Type: int32[n*2] (acamera_metadata_enum_android_request_available_dynamic_range_profiles_map_t)</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>Devices supporting the 10-bit output capability
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT">CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT</a>
+ * must list their supported dynamic range profiles. In case the camera is not able to
+ * support every possible profile combination within a single capture request, then the
+ * constraints must be listed here as well.</p>
+ */
+ ACAMERA_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP = // int32[n*2] (acamera_metadata_enum_android_request_available_dynamic_range_profiles_map_t)
+ ACAMERA_REQUEST_START + 19,
ACAMERA_REQUEST_END,
/**
@@ -3660,7 +3679,8 @@
* YUV_420_888 | all output sizes available for JPEG, up to the maximum video size | LIMITED |
* IMPLEMENTATION_DEFINED | same as YUV_420_888 | Any |</p>
* <p>For applications targeting SDK version 31 or newer, if the mobile device declares to be
- * <a href="https://developer.android.com/reference/android/os/Build/VERSION_CDOES/MEDIA_PERFORMANCE_CLASS.html">media performance class</a> S,
+ * media performance class 12 or higher by setting
+ * <a href="https://developer.android.com/reference/android/os/Build/VERSION_CDOES/MEDIA_PERFORMANCE_CLASS.html">MEDIA_PERFORMANCE_CLASS</a> to be 31 or larger,
* the primary camera devices (first rear/front camera in the camera ID list) will not
* support JPEG sizes smaller than 1080p. If the application configures a JPEG stream
* smaller than 1080p, the camera device will round up the JPEG image size to at least
@@ -3678,9 +3698,11 @@
* YUV_420_888 | all output sizes available for FULL hardware level, up to the maximum video size | LIMITED |
* IMPLEMENTATION_DEFINED | same as YUV_420_888 | Any |</p>
* <p>For applications targeting SDK version 31 or newer, if the mobile device doesn't declare
- * to be media performance class S, or if the camera device isn't a primary rear/front
- * camera, the minimum required output stream configurations are the same as for applications
- * targeting SDK version older than 31.</p>
+ * to be media performance class 12 or better by setting
+ * <a href="https://developer.android.com/reference/android/os/Build/VERSION_CDOES/MEDIA_PERFORMANCE_CLASS.html">MEDIA_PERFORMANCE_CLASS</a> to be 31 or larger,
+ * or if the camera device isn't a primary rear/front camera, the minimum required output
+ * stream configurations are the same as for applications targeting SDK version older than
+ * 31.</p>
* <p>Refer to ACAMERA_REQUEST_AVAILABLE_CAPABILITIES for additional
* mandatory stream configurations on a per-capability basis.</p>
* <p>Exception on 176x144 (QCIF) resolution: camera devices usually have a fixed capability for
@@ -9122,6 +9144,97 @@
} acamera_metadata_enum_android_request_available_capabilities_t;
+// ACAMERA_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP
+typedef enum acamera_metadata_enum_acamera_request_available_dynamic_range_profiles_map {
+ /**
+ * <p>8-bit SDR profile which is the default for all non 10-bit output capable devices.</p>
+ */
+ ACAMERA_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD = 0x1,
+
+ /**
+ * <p>10-bit pixel samples encoded using the Hybrid log-gamma transfer function.</p>
+ */
+ ACAMERA_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HLG10 = 0x2,
+
+ /**
+ * <p>10-bit pixel samples encoded using the SMPTE ST 2084 transfer function.
+ * This profile utilizes internal static metadata to increase the quality
+ * of the capture.</p>
+ */
+ ACAMERA_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10 = 0x4,
+
+ /**
+ * <p>10-bit pixel samples encoded using the SMPTE ST 2084 transfer function.
+ * In contrast to HDR10, this profile uses internal per-frame metadata
+ * to further enhance the quality of the capture.</p>
+ */
+ ACAMERA_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10_PLUS = 0x8,
+
+ /**
+ * <p>This is a camera mode for Dolby Vision capture optimized for a more scene
+ * accurate capture. This would typically differ from what a specific device
+ * might want to tune for a consumer optimized Dolby Vision general capture.</p>
+ */
+ ACAMERA_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF
+ = 0x10,
+
+ /**
+ * <p>This is the power optimized mode for 10-bit Dolby Vision HDR Reference Mode.</p>
+ */
+ ACAMERA_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF_PO
+ = 0x20,
+
+ /**
+ * <p>This is the camera mode for the default Dolby Vision capture mode for the
+ * specific device. This would be tuned by each specific device for consumer
+ * pleasing results that resonate with their particular audience. We expect
+ * that each specific device would have a different look for their default
+ * Dolby Vision capture.</p>
+ */
+ ACAMERA_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM
+ = 0x40,
+
+ /**
+ * <p>This is the power optimized mode for 10-bit Dolby Vision HDR device specific
+ * capture Mode.</p>
+ */
+ ACAMERA_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM_PO
+ = 0x80,
+
+ /**
+ * <p>This is the 8-bit version of the Dolby Vision reference capture mode optimized
+ * for scene accuracy.</p>
+ */
+ ACAMERA_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF
+ = 0x100,
+
+ /**
+ * <p>This is the power optimized mode for 8-bit Dolby Vision HDR Reference Mode.</p>
+ */
+ ACAMERA_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF_PO
+ = 0x200,
+
+ /**
+ * <p>This is the 8-bit version of device specific tuned and optimized Dolby Vision
+ * capture mode.</p>
+ */
+ ACAMERA_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM
+ = 0x400,
+
+ /**
+ * <p>This is the power optimized mode for 8-bit Dolby Vision HDR device specific
+ * capture Mode.</p>
+ */
+ ACAMERA_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM_PO
+ = 0x800,
+
+ /**
+ *
+ */
+ ACAMERA_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_MAX = 0x1000,
+
+} acamera_metadata_enum_android_request_available_dynamic_range_profiles_map_t;
+
// ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS
typedef enum acamera_metadata_enum_acamera_scaler_available_stream_configurations {
@@ -9213,6 +9326,20 @@
= 0x7,
/**
+ * <p>If supported, the recommended 10-bit output stream configurations must include
+ * a subset of the advertised <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YCBCR_P010">ImageFormat#YCBCR_P010</a> and
+ * <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#PRIVATE">ImageFormat#PRIVATE</a> outputs that are optimized for power
+ * and performance when registered along with a supported 10-bit dynamic range profile.
+ * see android.hardware.camera2.params.OutputConfiguration#setDynamicRangeProfile for
+ * details.</p>
+ */
+ ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_10BIT_OUTPUT
+ = 0x8,
+
+ ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_PUBLIC_END_3_8
+ = 0x9,
+
+ /**
* <p>Vendor defined use cases. These depend on the vendor implementation.</p>
*/
ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_VENDOR_START
diff --git a/camera/ndk/libcamera2ndk.map.txt b/camera/ndk/libcamera2ndk.map.txt
index 2b630db..b3977ff 100644
--- a/camera/ndk/libcamera2ndk.map.txt
+++ b/camera/ndk/libcamera2ndk.map.txt
@@ -2,11 +2,15 @@
global:
ACameraCaptureSession_abortCaptures;
ACameraCaptureSession_capture;
+ ACameraCaptureSession_captureV2; # introduced=33
ACameraCaptureSession_logicalCamera_capture; # introduced=29
+ ACameraCaptureSession_logicalCamera_captureV2; # introduced=33
ACameraCaptureSession_close;
ACameraCaptureSession_getDevice;
ACameraCaptureSession_setRepeatingRequest;
+ ACameraCaptureSession_setRepeatingRequestV2; # introduced=33
ACameraCaptureSession_logicalCamera_setRepeatingRequest; # introduced=29
+ ACameraCaptureSession_logicalCamera_setRepeatingRequestV2; # introduced=33
ACameraCaptureSession_stopRepeating;
ACameraCaptureSession_updateSharedOutput; # introduced=28
ACameraDevice_close;
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
index 9f63099..4cc1292 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
@@ -29,8 +29,6 @@
#include "ACaptureRequest.h"
#include "utils.h"
-#include "ACameraCaptureSession.inc"
-
#define CHECK_TRANSACTION_AND_RET(remoteRet, status, callName) \
if (!remoteRet.isOk()) { \
ALOGE("%s: Transaction error during %s call %s", __FUNCTION__, callName, \
@@ -910,6 +908,7 @@
case kWhatOnError:
case kWhatSessionStateCb:
case kWhatCaptureStart:
+ case kWhatCaptureStart2:
case kWhatCaptureResult:
case kWhatLogicalCaptureResult:
case kWhatCaptureFail:
@@ -982,6 +981,7 @@
}
case kWhatSessionStateCb:
case kWhatCaptureStart:
+ case kWhatCaptureStart2:
case kWhatCaptureResult:
case kWhatLogicalCaptureResult:
case kWhatCaptureFail:
@@ -1002,6 +1002,7 @@
const char *id_cstr = mId.c_str();
switch (msg->what()) {
case kWhatCaptureStart:
+ case kWhatCaptureStart2:
case kWhatCaptureResult:
case kWhatLogicalCaptureResult:
case kWhatCaptureFail:
@@ -1053,6 +1054,35 @@
freeACaptureRequest(request);
break;
}
+ case kWhatCaptureStart2:
+ {
+ ACameraCaptureSession_captureCallback_startV2 onStart2;
+ found = msg->findPointer(kCallbackFpKey, (void**) &onStart2);
+ if (!found) {
+ ALOGE("%s: Cannot find capture startV2 callback!", __FUNCTION__);
+ return;
+ }
+ if (onStart2 == nullptr) {
+ return;
+ }
+ int64_t timestamp;
+ found = msg->findInt64(kTimeStampKey, ×tamp);
+ if (!found) {
+ ALOGE("%s: Cannot find timestamp!", __FUNCTION__);
+ return;
+ }
+ int64_t frameNumber;
+ found = msg->findInt64(kFrameNumberKey, &frameNumber);
+ if (!found) {
+ ALOGE("%s: Cannot find frame number!", __FUNCTION__);
+ return;
+ }
+
+ ACaptureRequest* request = allocateACaptureRequest(requestSp, id_cstr);
+ (*onStart2)(context, session.get(), request, timestamp, frameNumber);
+ freeACaptureRequest(request);
+ break;
+ }
case kWhatCaptureResult:
{
ACameraCaptureSession_captureCallback_result onResult;
@@ -1281,6 +1311,7 @@
ACameraCaptureSession_captureCallbacks* cbs) :
mSession(session), mRequests(requests),
mIsRepeating(isRepeating),
+ mIs2Callback(false),
mIsLogicalCameraCallback(false) {
initCaptureCallbacks(cbs);
@@ -1297,6 +1328,7 @@
ACameraCaptureSession_logicalCamera_captureCallbacks* lcbs) :
mSession(session), mRequests(requests),
mIsRepeating(isRepeating),
+ mIs2Callback(false),
mIsLogicalCameraCallback(true) {
initCaptureCallbacks(lcbs);
@@ -1306,6 +1338,40 @@
}
}
+CameraDevice::CallbackHolder::CallbackHolder(
+ sp<ACameraCaptureSession> session,
+ const Vector<sp<CaptureRequest> >& requests,
+ bool isRepeating,
+ ACameraCaptureSession_captureCallbacksV2* cbs) :
+ mSession(session), mRequests(requests),
+ mIsRepeating(isRepeating),
+ mIs2Callback(true),
+ mIsLogicalCameraCallback(false) {
+ initCaptureCallbacksV2(cbs);
+
+ if (cbs != nullptr) {
+ mOnCaptureCompleted = cbs->onCaptureCompleted;
+ mOnCaptureFailed = cbs->onCaptureFailed;
+ }
+}
+
+CameraDevice::CallbackHolder::CallbackHolder(
+ sp<ACameraCaptureSession> session,
+ const Vector<sp<CaptureRequest> >& requests,
+ bool isRepeating,
+ ACameraCaptureSession_logicalCamera_captureCallbacksV2* lcbs) :
+ mSession(session), mRequests(requests),
+ mIsRepeating(isRepeating),
+ mIs2Callback(true),
+ mIsLogicalCameraCallback(true) {
+ initCaptureCallbacksV2(lcbs);
+
+ if (lcbs != nullptr) {
+ mOnLogicalCameraCaptureCompleted = lcbs->onLogicalCameraCaptureCompleted;
+ mOnLogicalCameraCaptureFailed = lcbs->onLogicalCameraCaptureFailed;
+ }
+}
+
void
CameraDevice::checkRepeatingSequenceCompleteLocked(
const int sequenceId, const int64_t lastFrameNumber) {
@@ -1542,11 +1608,14 @@
int32_t sequenceId = resultExtras.requestId;
int32_t burstId = resultExtras.burstId;
+ int64_t frameNumber = resultExtras.frameNumber;
auto it = dev->mSequenceCallbackMap.find(sequenceId);
if (it != dev->mSequenceCallbackMap.end()) {
CallbackHolder cbh = (*it).second;
ACameraCaptureSession_captureCallback_start onStart = cbh.mOnCaptureStarted;
+ ACameraCaptureSession_captureCallback_startV2 onStart2 = cbh.mOnCaptureStarted2;
+ bool v2Callback = cbh.mIs2Callback;
sp<ACameraCaptureSession> session = cbh.mSession;
if ((size_t) burstId >= cbh.mRequests.size()) {
ALOGE("%s: Error: request index %d out of bound (size %zu)",
@@ -1554,12 +1623,19 @@
dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
}
sp<CaptureRequest> request = cbh.mRequests[burstId];
- sp<AMessage> msg = new AMessage(kWhatCaptureStart, dev->mHandler);
+ sp<AMessage> msg = nullptr;
+ if (v2Callback) {
+ msg = new AMessage(kWhatCaptureStart2, dev->mHandler);
+ msg->setPointer(kCallbackFpKey, (void*) onStart2);
+ } else {
+ msg = new AMessage(kWhatCaptureStart, dev->mHandler);
+ msg->setPointer(kCallbackFpKey, (void*) onStart);
+ }
msg->setPointer(kContextKey, cbh.mContext);
msg->setObject(kSessionSpKey, session);
- msg->setPointer(kCallbackFpKey, (void*) onStart);
msg->setObject(kCaptureRequestKey, request);
msg->setInt64(kTimeStampKey, timestamp);
+ msg->setInt64(kFrameNumberKey, frameNumber);
dev->postSessionMsgAndCleanup(msg);
}
return ret;
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.h b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
index 0b6c7c8..c306206 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDevice.h
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
@@ -245,6 +245,7 @@
kWhatSessionStateCb, // onReady, onActive
// Capture callbacks
kWhatCaptureStart, // onCaptureStarted
+ kWhatCaptureStart2, // onCaptureStarted2
kWhatCaptureResult, // onCaptureProgressed, onCaptureCompleted
kWhatLogicalCaptureResult, // onLogicalCameraCaptureCompleted
kWhatCaptureFail, // onCaptureFailed
@@ -309,11 +310,18 @@
const Vector<sp<CaptureRequest>>& requests,
bool isRepeating,
ACameraCaptureSession_logicalCamera_captureCallbacks* lcbs);
-
- template <class T>
- void initCaptureCallbacks(T* cbs) {
+ CallbackHolder(sp<ACameraCaptureSession> session,
+ const Vector<sp<CaptureRequest> >& requests,
+ bool isRepeating,
+ ACameraCaptureSession_captureCallbacksV2* cbs);
+ CallbackHolder(sp<ACameraCaptureSession> session,
+ const Vector<sp<CaptureRequest> >& requests,
+ bool isRepeating,
+ ACameraCaptureSession_logicalCamera_captureCallbacksV2* lcbs);
+ void clearCallbacks() {
mContext = nullptr;
mOnCaptureStarted = nullptr;
+ mOnCaptureStarted2 = nullptr;
mOnCaptureProgressed = nullptr;
mOnCaptureCompleted = nullptr;
mOnLogicalCameraCaptureCompleted = nullptr;
@@ -322,6 +330,24 @@
mOnCaptureSequenceCompleted = nullptr;
mOnCaptureSequenceAborted = nullptr;
mOnCaptureBufferLost = nullptr;
+ }
+
+ template <class T>
+ void initCaptureCallbacksV2(T* cbs) {
+ clearCallbacks();
+ if (cbs != nullptr) {
+ mContext = cbs->context;
+ mOnCaptureStarted2 = cbs->onCaptureStarted;
+ mOnCaptureProgressed = cbs->onCaptureProgressed;
+ mOnCaptureSequenceCompleted = cbs->onCaptureSequenceCompleted;
+ mOnCaptureSequenceAborted = cbs->onCaptureSequenceAborted;
+ mOnCaptureBufferLost = cbs->onCaptureBufferLost;
+ }
+ }
+
+ template <class T>
+ void initCaptureCallbacks(T* cbs) {
+ clearCallbacks();
if (cbs != nullptr) {
mContext = cbs->context;
mOnCaptureStarted = cbs->onCaptureStarted;
@@ -335,10 +361,12 @@
sp<ACameraCaptureSession> mSession;
Vector<sp<CaptureRequest>> mRequests;
const bool mIsRepeating;
+ const bool mIs2Callback;
const bool mIsLogicalCameraCallback;
void* mContext;
ACameraCaptureSession_captureCallback_start mOnCaptureStarted;
+ ACameraCaptureSession_captureCallback_startV2 mOnCaptureStarted2;
ACameraCaptureSession_captureCallback_result mOnCaptureProgressed;
ACameraCaptureSession_captureCallback_result mOnCaptureCompleted;
ACameraCaptureSession_logicalCamera_captureCallback_result mOnLogicalCameraCaptureCompleted;
diff --git a/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp b/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
index ba14c5c..63cdb76 100644
--- a/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
+++ b/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
@@ -236,6 +236,11 @@
return ACameraCaptureSession_capture(mSession, &mCaptureCallbacks, 1, &mStillRequest,
&seqId);
}
+ int takePicture2() {
+ int seqId;
+ return ACameraCaptureSession_captureV2(mSession, &mCaptureCallbacksV2, 1,
+ &mStillRequest, &seqId);
+ }
int takeLogicalCameraPicture() {
int seqId;
@@ -243,15 +248,31 @@
1, &mStillRequest, &seqId);
}
+ int takeLogicalCameraPicture2() {
+ int seqId;
+ return ACameraCaptureSession_logicalCamera_captureV2(mSession,
+ &mLogicalCaptureCallbacksV2, 1, &mStillRequest, &seqId);
+ }
+
bool checkCallbacks(int pictureCount) {
std::lock_guard<std::mutex> lock(mMutex);
if (mCompletedCaptureCallbackCount != pictureCount) {
- ALOGE("Completed capture callaback count not as expected. expected %d actual %d",
+ ALOGE("Completed capture callback count not as expected. expected %d actual %d",
pictureCount, mCompletedCaptureCallbackCount);
return false;
}
return true;
}
+ bool checkCallbacksV2(int pictureCount) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mCaptureStartedCallbackCount != pictureCount) {
+ ALOGE("Capture started callback count not as expected. expected %d actual %d",
+ pictureCount, mCaptureStartedCallbackCount);
+ return false;
+ }
+ return true;
+ }
+
private:
ACameraDevice_StateCallbacks mDeviceCb{this, nullptr, nullptr};
@@ -276,6 +297,7 @@
const char* mCameraId;
ACameraManager* mCameraManager;
int mCompletedCaptureCallbackCount = 0;
+ int mCaptureStartedCallbackCount = 0;
std::mutex mMutex;
ACameraCaptureSession_captureCallbacks mCaptureCallbacks = {
// TODO: Add tests for other callbacks
@@ -293,8 +315,25 @@
nullptr, // onCaptureSequenceAborted
nullptr, // onCaptureBufferLost
};
+ ACameraCaptureSession_captureCallbacksV2 mCaptureCallbacksV2 = {
+ this, // context
+ [](void* ctx , ACameraCaptureSession *,const ACaptureRequest *, int64_t,
+ int64_t frameNumber ) {
+ CameraHelper *ch = static_cast<CameraHelper *>(ctx);
+ ASSERT_TRUE(frameNumber >= 0);
+ std::lock_guard<std::mutex> lock(ch->mMutex);
+ ch->mCaptureStartedCallbackCount++;
+ },
+ nullptr, // onCaptureProgressed
+ nullptr, // onCaptureCompleted
+ nullptr, // onCaptureFailed
+ nullptr, // onCaptureSequenceCompleted
+ nullptr, // onCaptureSequenceAborted
+ nullptr, // onCaptureBufferLost
+ };
std::vector<std::string> mPhysicalCameraIds;
+
ACameraCaptureSession_logicalCamera_captureCallbacks mLogicalCaptureCallbacks = {
// TODO: Add tests for other callbacks
this, // context
@@ -336,6 +375,23 @@
nullptr, // onCaptureSequenceAborted
nullptr, // onCaptureBufferLost
};
+ ACameraCaptureSession_logicalCamera_captureCallbacksV2 mLogicalCaptureCallbacksV2 = {
+ this, // context
+ [](void* ctx , ACameraCaptureSession *,const ACaptureRequest *, int64_t,
+ int64_t frameNumber) {
+ CameraHelper *ch = static_cast<CameraHelper *>(ctx);
+ ASSERT_TRUE(frameNumber >= 0);
+ std::lock_guard<std::mutex> lock(ch->mMutex);
+ ch->mCaptureStartedCallbackCount++;
+ },
+ nullptr, // onCaptureProgressed
+ nullptr, //onLogicalCaptureCompleted
+ nullptr, //onLogicalCpatureFailed
+ nullptr, // onCaptureSequenceCompleted
+ nullptr, // onCaptureSequenceAborted
+ nullptr, // onCaptureBufferLost
+ };
+
};
class ImageReaderTestCase {
@@ -570,7 +626,7 @@
}
bool takePictures(const char* id, uint64_t readerUsage, int readerMaxImages,
- bool readerAsync, int pictureCount) {
+ bool readerAsync, int pictureCount, bool v2 = false) {
int ret = 0;
ImageReaderTestCase testCase(
@@ -600,7 +656,11 @@
}
for (int i = 0; i < pictureCount; i++) {
- ret = cameraHelper.takePicture();
+ if (v2) {
+ ret = cameraHelper.takePicture2();
+ } else {
+ ret = cameraHelper.takePicture();
+ }
if (ret < 0) {
ALOGE("Unable to take picture");
return false;
@@ -617,7 +677,8 @@
}
}
return testCase.getAcquiredImageCount() == pictureCount &&
- cameraHelper.checkCallbacks(pictureCount);
+ v2 ? cameraHelper.checkCallbacksV2(pictureCount) :
+ cameraHelper.checkCallbacks(pictureCount);
}
bool testTakePicturesNative(const char* id) {
@@ -626,12 +687,14 @@
for (auto& readerMaxImages : {1, 4, 8}) {
for (auto& readerAsync : {true, false}) {
for (auto& pictureCount : {1, 4, 8}) {
- if (!takePictures(id, readerUsage, readerMaxImages,
- readerAsync, pictureCount)) {
- ALOGE("Test takePictures failed for test case usage=%" PRIu64
- ", maxImages=%d, async=%d, pictureCount=%d",
- readerUsage, readerMaxImages, readerAsync, pictureCount);
- return false;
+ for ( auto & v2 : {true, false}) {
+ if (!takePictures(id, readerUsage, readerMaxImages,
+ readerAsync, pictureCount, v2)) {
+ ALOGE("Test takePictures failed for test case usage=%" PRIu64
+ ", maxImages=%d, async=%d, pictureCount=%d",
+ readerUsage, readerMaxImages, readerAsync, pictureCount);
+ return false;
+ }
}
}
}
@@ -725,7 +788,7 @@
return;
}
- void testLogicalCameraPhysicalStream(bool usePhysicalSettings) {
+ void testLogicalCameraPhysicalStream(bool usePhysicalSettings, bool v2) {
const char* cameraId = nullptr;
ACameraMetadata* staticMetadata = nullptr;
std::vector<const char*> physicalCameraIds;
@@ -772,7 +835,12 @@
}
for (int i = 0; i < pictureCount; i++) {
- ret = cameraHelper.takeLogicalCameraPicture();
+ if (v2) {
+ ret = cameraHelper.takeLogicalCameraPicture2();
+ }
+ else {
+ ret = cameraHelper.takeLogicalCameraPicture();
+ }
ASSERT_EQ(ret, 0);
}
@@ -793,8 +861,11 @@
ALOGI("Testing window %p", testCase->getNativeWindow());
ASSERT_EQ(testCase->getAcquiredImageCount(), pictureCount);
}
-
- ASSERT_TRUE(cameraHelper.checkCallbacks(pictureCount));
+ if (v2) {
+ ASSERT_TRUE(cameraHelper.checkCallbacksV2(pictureCount));
+ } else {
+ ASSERT_TRUE(cameraHelper.checkCallbacks(pictureCount));
+ }
ACameraMetadata_free(staticMetadata);
}
@@ -834,8 +905,10 @@
}
TEST_F(AImageReaderVendorTest, LogicalCameraPhysicalStream) {
- testLogicalCameraPhysicalStream(false/*usePhysicalSettings*/);
- testLogicalCameraPhysicalStream(true/*usePhysicalSettings*/);
+ for (auto & v2 : {true, false}) {
+ testLogicalCameraPhysicalStream(false/*usePhysicalSettings*/, v2);
+ testLogicalCameraPhysicalStream(true/*usePhysicalSettings*/, v2);
+ }
}
} // namespace
diff --git a/camera/tests/CameraBinderTests.cpp b/camera/tests/CameraBinderTests.cpp
index 9f2f430..17ea512 100644
--- a/camera/tests/CameraBinderTests.cpp
+++ b/camera/tests/CameraBinderTests.cpp
@@ -96,6 +96,12 @@
return binder::Status::ok();
};
+ virtual binder::Status onTorchStrengthLevelChanged(const String16& /*cameraId*/,
+ int32_t /*torchStrength*/) {
+ // No op
+ return binder::Status::ok();
+ }
+
virtual binder::Status onCameraAccessPrioritiesChanged() {
// No op
return binder::Status::ok();
diff --git a/cmds/stagefright/Android.bp b/cmds/stagefright/Android.bp
index c4783d3..e1fe07e 100644
--- a/cmds/stagefright/Android.bp
+++ b/cmds/stagefright/Android.bp
@@ -227,8 +227,6 @@
"rs-headers",
],
- include_dirs: ["frameworks/av/media/libstagefright"],
-
shared_libs: [
"libstagefright",
"liblog",
diff --git a/drm/mediadrm/plugins/clearkey/aidl/Android.bp b/drm/mediadrm/plugins/clearkey/aidl/Android.bp
new file mode 100644
index 0000000..2997b67
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/aidl/Android.bp
@@ -0,0 +1,72 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_av_license"],
+}
+
+cc_defaults {
+ name: "aidl_clearkey_service_defaults",
+ vendor: true,
+
+ srcs: [
+ "CreatePluginFactories.cpp",
+ "CryptoFactory.cpp",
+ "CryptoPlugin.cpp",
+ "DrmFactory.cpp",
+ "DrmPlugin.cpp",
+ ],
+
+ relative_install_path: "hw",
+
+ cflags: ["-Wall", "-Werror", "-Wthread-safety"],
+
+ include_dirs: ["frameworks/av/include"],
+
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "libcrypto",
+ "liblog",
+ "libprotobuf-cpp-lite",
+ "libutils",
+ "android.hardware.drm-V1-ndk",
+ ],
+
+ static_libs: [
+ "android.hardware.common-V2-ndk",
+ "libclearkeybase",
+ ],
+
+ local_include_dirs: ["include"],
+
+ sanitize: {
+ integer_overflow: true,
+ },
+}
+
+cc_binary {
+ name: "android.hardware.drm-service.clearkey",
+ defaults: ["aidl_clearkey_service_defaults"],
+ srcs: ["Service.cpp"],
+ init_rc: ["android.hardware.drm-service.clearkey.rc"],
+ vintf_fragments: ["android.hardware.drm-service.clearkey.xml"],
+}
+
+cc_binary {
+ name: "android.hardware.drm-service-lazy.clearkey",
+ defaults: ["aidl_clearkey_service_defaults"],
+ overrides: ["android.hardware.drm-service.clearkey"],
+ srcs: ["ServiceLazy.cpp"],
+ init_rc: ["android.hardware.drm-service-lazy.clearkey.rc"],
+ vintf_fragments: ["android.hardware.drm-service.clearkey.xml"],
+}
+
+phony {
+ name: "android.hardware.drm@latest-service.clearkey",
+ required: [
+ "android.hardware.drm-service.clearkey",
+ ],
+}
diff --git a/drm/mediadrm/plugins/clearkey/aidl/CreatePluginFactories.cpp b/drm/mediadrm/plugins/clearkey/aidl/CreatePluginFactories.cpp
new file mode 100644
index 0000000..5f6bfe8
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/aidl/CreatePluginFactories.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "CreatePluginFactories.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace drm {
+namespace clearkey {
+
+std::shared_ptr<DrmFactory> createDrmFactory() {
+ return ::ndk::SharedRefBase::make<DrmFactory>();
+}
+
+std::shared_ptr<CryptoFactory> createCryptoFactory() {
+ return ::ndk::SharedRefBase::make<CryptoFactory>();
+}
+
+} // namespace clearkey
+} // namespace drm
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/drm/mediadrm/plugins/clearkey/aidl/CryptoFactory.cpp b/drm/mediadrm/plugins/clearkey/aidl/CryptoFactory.cpp
new file mode 100644
index 0000000..43b325d
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/aidl/CryptoFactory.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "clearkey-CryptoFactory"
+#include <utils/Log.h>
+
+#include "CryptoFactory.h"
+
+#include "ClearKeyUUID.h"
+#include "CryptoPlugin.h"
+#include "AidlUtils.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace drm {
+namespace clearkey {
+
+using ::aidl::android::hardware::drm::Status;
+using ::aidl::android::hardware::drm::Uuid;
+
+using std::vector;
+
+::ndk::ScopedAStatus CryptoFactory::createPlugin(
+ const ::aidl::android::hardware::drm::Uuid& in_uuid,
+ const std::vector<uint8_t>& in_initData,
+ std::shared_ptr<::aidl::android::hardware::drm::ICryptoPlugin>* _aidl_return) {
+ if (!isClearKeyUUID(in_uuid.uuid.data())) {
+ ALOGE("Clearkey Drm HAL: failed to create crypto plugin, "
+ "invalid crypto scheme");
+ *_aidl_return = nullptr;
+ return toNdkScopedAStatus(Status::BAD_VALUE);
+ }
+
+ std::shared_ptr<CryptoPlugin> plugin = ::ndk::SharedRefBase::make<CryptoPlugin>(in_initData);
+ Status status = plugin->getInitStatus();
+ if (status != Status::OK) {
+ plugin.reset();
+ plugin = nullptr;
+ }
+ *_aidl_return = plugin;
+ return toNdkScopedAStatus(status);
+}
+
+::ndk::ScopedAStatus CryptoFactory::isCryptoSchemeSupported(const Uuid& in_uuid,
+ bool* _aidl_return) {
+ *_aidl_return = isClearKeyUUID(in_uuid.uuid.data());
+ return ::ndk::ScopedAStatus::ok();
+}
+
+} // namespace clearkey
+} // namespace drm
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/drm/mediadrm/plugins/clearkey/aidl/CryptoPlugin.cpp b/drm/mediadrm/plugins/clearkey/aidl/CryptoPlugin.cpp
new file mode 100644
index 0000000..b65d40f
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/aidl/CryptoPlugin.cpp
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "clearkey-CryptoPlugin"
+
+#include <utils/Log.h>
+#include <cerrno>
+#include <cstring>
+
+#include "CryptoPlugin.h"
+#include "SessionLibrary.h"
+#include "AidlUtils.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace drm {
+namespace clearkey {
+
+using ::aidl::android::hardware::drm::Status;
+
+::ndk::ScopedAStatus CryptoPlugin::decrypt(
+ bool in_secure, const std::vector<uint8_t>& in_keyId, const std::vector<uint8_t>& in_iv,
+ ::aidl::android::hardware::drm::Mode in_mode,
+ const ::aidl::android::hardware::drm::Pattern& in_pattern,
+ const std::vector<::aidl::android::hardware::drm::SubSample>& in_subSamples,
+ const ::aidl::android::hardware::drm::SharedBuffer& in_source, int64_t in_offset,
+ const ::aidl::android::hardware::drm::DestinationBuffer& in_destination,
+ ::aidl::android::hardware::drm::DecryptResult* _aidl_return) {
+ UNUSED(in_pattern);
+
+ std::string detailedError;
+
+ _aidl_return->bytesWritten = 0;
+ if (in_secure) {
+ _aidl_return->detailedError = "secure decryption is not supported with ClearKey";
+ return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
+ }
+
+ std::lock_guard<std::mutex> shared_buffer_lock(mSharedBufferLock);
+ if (mSharedBufferMap.find(in_source.bufferId) == mSharedBufferMap.end()) {
+ _aidl_return->detailedError = "source decrypt buffer base not set";
+ return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
+ }
+
+ if (in_destination.type == BufferType::SHARED_MEMORY) {
+ const SharedBuffer& dest = in_destination.nonsecureMemory;
+ if (mSharedBufferMap.find(dest.bufferId) == mSharedBufferMap.end()) {
+ _aidl_return->detailedError = "destination decrypt buffer base not set";
+ return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
+ }
+ } else {
+ _aidl_return->detailedError = "destination type not supported";
+ return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
+ }
+
+ auto src = mSharedBufferMap[in_source.bufferId];
+ if (src->mBase == nullptr) {
+ _aidl_return->detailedError = "source is a nullptr";
+ return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
+ }
+
+ size_t totalSize = 0;
+ if (__builtin_add_overflow(in_source.offset, in_offset, &totalSize) ||
+ __builtin_add_overflow(totalSize, in_source.size, &totalSize) || totalSize > src->mSize) {
+ android_errorWriteLog(0x534e4554, "176496160");
+ _aidl_return->detailedError = "invalid buffer size";
+ return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
+ }
+
+ // destination.type == BufferType::SHARED_MEMORY
+ const SharedBuffer& destBuffer = in_destination.nonsecureMemory;
+ auto dest = mSharedBufferMap[destBuffer.bufferId];
+ if (dest->mBase == nullptr) {
+ _aidl_return->detailedError = "destination is a nullptr";
+ return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
+ }
+
+ totalSize = 0;
+ if (__builtin_add_overflow(destBuffer.offset, destBuffer.size, &totalSize) ||
+ totalSize > dest->mSize) {
+ android_errorWriteLog(0x534e4554, "176444622");
+ _aidl_return->detailedError = "invalid buffer size";
+ return toNdkScopedAStatus(Status::ERROR_DRM_FRAME_TOO_LARGE);
+ }
+
+ // Calculate the output buffer size and determine if any subsamples are
+ // encrypted.
+ uint8_t* srcPtr = src->mBase + in_source.offset + in_offset;
+ uint8_t* destPtr = dest->mBase + in_destination.nonsecureMemory.offset;
+ size_t destSize = 0;
+ size_t srcSize = 0;
+ bool haveEncryptedSubsamples = false;
+ for (size_t i = 0; i < in_subSamples.size(); i++) {
+ const SubSample& subSample = in_subSamples[i];
+ if (__builtin_add_overflow(destSize, subSample.numBytesOfClearData, &destSize) ||
+ __builtin_add_overflow(srcSize, subSample.numBytesOfClearData, &srcSize)) {
+ _aidl_return->detailedError = "subsample clear size overflow";
+ return toNdkScopedAStatus(Status::ERROR_DRM_FRAME_TOO_LARGE);
+ }
+ if (__builtin_add_overflow(destSize, subSample.numBytesOfEncryptedData, &destSize) ||
+ __builtin_add_overflow(srcSize, subSample.numBytesOfEncryptedData, &srcSize)) {
+ _aidl_return->detailedError = "subsample encrypted size overflow";
+ return toNdkScopedAStatus(Status::ERROR_DRM_FRAME_TOO_LARGE);
+ }
+ if (subSample.numBytesOfEncryptedData > 0) {
+ haveEncryptedSubsamples = true;
+ }
+ }
+
+ if (destSize > destBuffer.size || srcSize > in_source.size) {
+ _aidl_return->detailedError = "subsample sum too large";
+ return toNdkScopedAStatus(Status::ERROR_DRM_FRAME_TOO_LARGE);
+ }
+
+ if (in_mode == Mode::UNENCRYPTED) {
+ if (haveEncryptedSubsamples) {
+ _aidl_return->detailedError =
+ "Encrypted subsamples found in allegedly unencrypted data.";
+ return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
+ }
+
+ size_t offset = 0;
+ for (size_t i = 0; i < in_subSamples.size(); ++i) {
+ const SubSample& subSample = in_subSamples[i];
+ if (subSample.numBytesOfClearData != 0) {
+ memcpy(reinterpret_cast<uint8_t*>(destPtr) + offset,
+ reinterpret_cast<const uint8_t*>(srcPtr) + offset,
+ subSample.numBytesOfClearData);
+ offset += subSample.numBytesOfClearData;
+ }
+ }
+
+ _aidl_return->bytesWritten = static_cast<ssize_t>(offset);
+ _aidl_return->detailedError = "";
+ return toNdkScopedAStatus(Status::OK);
+ } else if (in_mode == Mode::AES_CTR) {
+ size_t bytesDecrypted{};
+ std::vector<int32_t> clearDataLengths;
+ std::vector<int32_t> encryptedDataLengths;
+ for (auto ss : in_subSamples) {
+ clearDataLengths.push_back(ss.numBytesOfClearData);
+ encryptedDataLengths.push_back(ss.numBytesOfEncryptedData);
+ }
+ auto res =
+ mSession->decrypt(in_keyId.data(), in_iv.data(),
+ srcPtr, static_cast<uint8_t*>(destPtr),
+ clearDataLengths, encryptedDataLengths,
+ &bytesDecrypted);
+ if (res == clearkeydrm::OK) {
+ _aidl_return->bytesWritten = static_cast<ssize_t>(bytesDecrypted);
+ _aidl_return->detailedError = "";
+ return toNdkScopedAStatus(Status::OK);
+ } else {
+ _aidl_return->bytesWritten = 0;
+ _aidl_return->detailedError = "Decryption Error";
+ return toNdkScopedAStatus(static_cast<Status>(res));
+ }
+ } else {
+ _aidl_return->bytesWritten = 0;
+ _aidl_return->detailedError =
+ "selected encryption mode is not supported by the ClearKey DRM \
+Plugin";
+ return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
+ }
+}
+
+::ndk::ScopedAStatus CryptoPlugin::getLogMessages(
+ std::vector<::aidl::android::hardware::drm::LogMessage>* _aidl_return) {
+ using std::chrono::duration_cast;
+ using std::chrono::milliseconds;
+ using std::chrono::system_clock;
+
+ auto timeMillis = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
+
+ std::vector<::aidl::android::hardware::drm::LogMessage> logs = {
+ {timeMillis, ::aidl::android::hardware::drm::LogPriority::ERROR,
+ std::string("Not implemented")}};
+ *_aidl_return = logs;
+ return toNdkScopedAStatus(Status::OK);
+}
+
+::ndk::ScopedAStatus CryptoPlugin::notifyResolution(int32_t in_width, int32_t in_height) {
+ UNUSED(in_width);
+ UNUSED(in_height);
+ return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus CryptoPlugin::requiresSecureDecoderComponent(const std::string& in_mime,
+ bool* _aidl_return) {
+ UNUSED(in_mime);
+ *_aidl_return = false;
+ return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus CryptoPlugin::setMediaDrmSession(const std::vector<uint8_t>& in_sessionId) {
+ Status status = Status::OK;
+ if (!in_sessionId.size()) {
+ mSession = nullptr;
+ } else {
+ mSession = SessionLibrary::get()->findSession(in_sessionId);
+ if (!mSession.get()) {
+ status = Status::ERROR_DRM_SESSION_NOT_OPENED;
+ }
+ }
+ return toNdkScopedAStatus(status);
+}
+
+::ndk::ScopedAStatus CryptoPlugin::setSharedBufferBase(
+ const ::aidl::android::hardware::common::Ashmem& in_base, int32_t in_bufferId) {
+ std::lock_guard<std::mutex> shared_buffer_lock(mSharedBufferLock);
+ mSharedBufferMap[in_bufferId] = std::make_shared<SharedBufferBase>(in_base);
+ return ::ndk::ScopedAStatus::ok();
+}
+
+SharedBufferBase::SharedBufferBase(const ::aidl::android::hardware::common::Ashmem& mem)
+ : mBase(nullptr),
+ mSize(mem.size) {
+ if (mem.fd.get() < 0) {
+ return;
+ }
+ auto addr = mmap(nullptr, mem.size, PROT_READ | PROT_WRITE, MAP_SHARED,
+ mem.fd.get(), 0);
+ if (addr == MAP_FAILED) {
+ ALOGE("mmap err: fd %d; errno %s",
+ mem.fd.get(), strerror(errno));
+ } else {
+ mBase = static_cast<uint8_t*>(addr);
+ }
+}
+
+SharedBufferBase::~SharedBufferBase() {
+ if (munmap(mBase, mSize)) {
+ ALOGE("munmap err: base %p; errno %s",
+ mBase, strerror(errno));
+ }
+}
+} // namespace clearkey
+} // namespace drm
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/drm/mediadrm/plugins/clearkey/aidl/DrmFactory.cpp b/drm/mediadrm/plugins/clearkey/aidl/DrmFactory.cpp
new file mode 100644
index 0000000..168a661
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/aidl/DrmFactory.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "clearkey-DrmFactory"
+
+#include <utils/Log.h>
+
+#include "DrmFactory.h"
+
+#include "ClearKeyUUID.h"
+#include "DrmPlugin.h"
+#include "MimeTypeStdStr.h"
+#include "SessionLibrary.h"
+#include "AidlUtils.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace drm {
+namespace clearkey {
+
+using std::string;
+using std::vector;
+
+using ::aidl::android::hardware::drm::SecurityLevel;
+using ::aidl::android::hardware::drm::Status;
+using ::aidl::android::hardware::drm::Uuid;
+
+::ndk::ScopedAStatus DrmFactory::createPlugin(
+ const Uuid& in_uuid, const string& in_appPackageName,
+ std::shared_ptr<::aidl::android::hardware::drm::IDrmPlugin>* _aidl_return) {
+ UNUSED(in_appPackageName);
+
+ if (!isClearKeyUUID(in_uuid.uuid.data())) {
+ ALOGE("Clearkey Drm HAL: failed to create drm plugin, "
+ "invalid crypto scheme");
+ *_aidl_return = nullptr;
+ return toNdkScopedAStatus(Status::BAD_VALUE);
+ }
+
+ std::shared_ptr<DrmPlugin> plugin =
+ ::ndk::SharedRefBase::make<DrmPlugin>(SessionLibrary::get());
+ *_aidl_return = plugin;
+ return toNdkScopedAStatus(Status::OK);
+}
+
+::ndk::ScopedAStatus DrmFactory::getSupportedCryptoSchemes(vector<Uuid>* _aidl_return) {
+ vector<Uuid> schemes;
+ Uuid scheme;
+ for (const auto& uuid : ::aidl::android::hardware::drm::clearkey::getSupportedCryptoSchemes()) {
+ scheme.uuid.assign(uuid.begin(), uuid.end());
+ schemes.push_back(scheme);
+ }
+ *_aidl_return = schemes;
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus DrmFactory::isContentTypeSupported(const string& in_mimeType,
+ bool* _aidl_return) {
+ // This should match the in_mimeTypes handed by InitDataParser.
+ *_aidl_return = in_mimeType == kIsoBmffVideoMimeType || in_mimeType == kIsoBmffAudioMimeType ||
+ in_mimeType == kCencInitDataFormat || in_mimeType == kWebmVideoMimeType ||
+ in_mimeType == kWebmAudioMimeType || in_mimeType == kWebmInitDataFormat;
+ return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus DrmFactory::isCryptoSchemeSupported(const Uuid& in_uuid,
+ const string& in_mimeType,
+ SecurityLevel in_securityLevel,
+ bool* _aidl_return) {
+ bool isSupportedMimeType = false;
+ if (!isContentTypeSupported(in_mimeType, &isSupportedMimeType).isOk()) {
+ ALOGD("%s mime type is not supported by crypto scheme", in_mimeType.c_str());
+ }
+ *_aidl_return = isClearKeyUUID(in_uuid.uuid.data()) && isSupportedMimeType &&
+ in_securityLevel == SecurityLevel::SW_SECURE_CRYPTO;
+ return ::ndk::ScopedAStatus::ok();
+}
+
+binder_status_t DrmFactory::dump(int fd, const char** args, uint32_t numArgs) {
+ UNUSED(args);
+ UNUSED(numArgs);
+
+ if (fd < 0) {
+ ALOGE("%s: negative fd", __FUNCTION__);
+ return STATUS_BAD_VALUE;
+ }
+
+ uint32_t currentSessions = SessionLibrary::get()->numOpenSessions();
+ dprintf(fd, "current open sessions: %u\n", currentSessions);
+
+ return STATUS_OK;
+}
+
+} // namespace clearkey
+} // namespace drm
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/drm/mediadrm/plugins/clearkey/aidl/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/aidl/DrmPlugin.cpp
new file mode 100644
index 0000000..92bea66
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/aidl/DrmPlugin.cpp
@@ -0,0 +1,1032 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "clearkey-DrmPlugin"
+
+#include <aidl/android/hardware/drm/DrmMetric.h>
+#include <utils/Log.h>
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <chrono>
+
+#include "AidlUtils.h"
+#include "ClearKeyDrmProperties.h"
+#include "DrmPlugin.h"
+#include "Session.h"
+#include "Utils.h"
+
+namespace {
+const std::string kKeySetIdPrefix("ckid");
+const int kKeySetIdLength = 16;
+const int kSecureStopIdStart = 100;
+const std::string kOfflineLicense("\"type\":\"persistent-license\"");
+const std::string kStreaming("Streaming");
+const std::string kTemporaryLicense("\"type\":\"temporary\"");
+const std::string kTrue("True");
+
+const std::string kQueryKeyLicenseType("LicenseType");
+// Value: "Streaming" or "Offline"
+const std::string kQueryKeyPlayAllowed("PlayAllowed");
+// Value: "True" or "False"
+const std::string kQueryKeyRenewAllowed("RenewAllowed");
+// Value: "True" or "False"
+
+const int kSecureStopIdSize = 10;
+
+std::vector<uint8_t> uint32ToVector(uint32_t value) {
+ // 10 bytes to display max value 4294967295 + one byte null terminator
+ char buffer[kSecureStopIdSize];
+ memset(buffer, 0, kSecureStopIdSize);
+ snprintf(buffer, kSecureStopIdSize, "%" PRIu32, value);
+ return std::vector<uint8_t>(buffer, buffer + sizeof(buffer));
+}
+
+}; // unnamed namespace
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace drm {
+namespace clearkey {
+
+using ::android::Mutex;
+
+DrmPlugin::DrmPlugin(SessionLibrary* sessionLibrary)
+ : mSessionLibrary(sessionLibrary),
+ mOpenSessionOkCount(0),
+ mCloseSessionOkCount(0),
+ mCloseSessionNotOpenedCount(0),
+ mNextSecureStopId(kSecureStopIdStart),
+ mMockError(Status::OK) {
+ mPlayPolicy.clear();
+ initProperties();
+ mSecureStops.clear();
+ mReleaseKeysMap.clear();
+ std::srand(std::time(nullptr));
+}
+
+void DrmPlugin::initProperties() {
+ mStringProperties.clear();
+ mStringProperties[kVendorKey] = kVendorValue;
+ mStringProperties[kVersionKey] = kVersionValue;
+ mStringProperties[kPluginDescriptionKey] = kPluginDescriptionValue;
+ mStringProperties[kAlgorithmsKey] = kAlgorithmsValue;
+ mStringProperties[kListenerTestSupportKey] = kListenerTestSupportValue;
+ mStringProperties[kDrmErrorTestKey] = kDrmErrorTestValue;
+
+ std::vector<uint8_t> valueVector;
+ valueVector.clear();
+ valueVector.insert(valueVector.end(), kTestDeviceIdData,
+ kTestDeviceIdData + sizeof(kTestDeviceIdData) / sizeof(uint8_t));
+ mByteArrayProperties[kDeviceIdKey] = valueVector;
+
+ valueVector.clear();
+ valueVector.insert(valueVector.end(), kMetricsData,
+ kMetricsData + sizeof(kMetricsData) / sizeof(uint8_t));
+ mByteArrayProperties[kMetricsKey] = valueVector;
+}
+
+// The secure stop in ClearKey implementation is not installed securely.
+// This function merely creates a test environment for testing secure stops APIs.
+// The content in this secure stop is implementation dependent, the clearkey
+// secureStop does not serve as a reference implementation.
+void DrmPlugin::installSecureStop(const std::vector<uint8_t>& sessionId) {
+ ::android::Mutex::Autolock lock(mSecureStopLock);
+
+ ClearkeySecureStop clearkeySecureStop;
+ clearkeySecureStop.id = uint32ToVector(++mNextSecureStopId);
+ clearkeySecureStop.data.assign(sessionId.begin(), sessionId.end());
+
+ mSecureStops.insert(std::pair<std::vector<uint8_t>, ClearkeySecureStop>(clearkeySecureStop.id,
+ clearkeySecureStop));
+}
+
+::ndk::ScopedAStatus DrmPlugin::closeSession(const std::vector<uint8_t>& in_sessionId) {
+ if (in_sessionId.size() == 0) {
+ return toNdkScopedAStatus(Status::BAD_VALUE);
+ }
+
+ ::android::sp<Session> session = mSessionLibrary->findSession(in_sessionId);
+ if (session.get()) {
+ mSessionLibrary->destroySession(session);
+ if (session->getMockError() != clearkeydrm::OK) {
+ sendSessionLostState(in_sessionId);
+ return toNdkScopedAStatus(Status::ERROR_DRM_INVALID_STATE);
+ }
+ mCloseSessionOkCount++;
+ return toNdkScopedAStatus(Status::OK);
+ }
+ mCloseSessionNotOpenedCount++;
+ return toNdkScopedAStatus(Status::ERROR_DRM_SESSION_NOT_OPENED);
+}
+
+::ndk::ScopedAStatus DrmPlugin::decrypt(const std::vector<uint8_t>& in_sessionId,
+ const std::vector<uint8_t>& in_keyId,
+ const std::vector<uint8_t>& in_input,
+ const std::vector<uint8_t>& in_iv,
+ std::vector<uint8_t>* _aidl_return) {
+ *_aidl_return = {};
+ if (in_sessionId.size() == 0 || in_keyId.size() == 0 || in_input.size() == 0 ||
+ in_iv.size() == 0) {
+ return toNdkScopedAStatus(Status::BAD_VALUE);
+ }
+ return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
+}
+
+::ndk::ScopedAStatus DrmPlugin::encrypt(const std::vector<uint8_t>& in_sessionId,
+ const std::vector<uint8_t>& in_keyId,
+ const std::vector<uint8_t>& in_input,
+ const std::vector<uint8_t>& in_iv,
+ std::vector<uint8_t>* _aidl_return) {
+ *_aidl_return = {};
+ if (in_sessionId.size() == 0 || in_keyId.size() == 0 || in_input.size() == 0 ||
+ in_iv.size() == 0) {
+ return toNdkScopedAStatus(Status::BAD_VALUE);
+ }
+ return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
+}
+
+::ndk::ScopedAStatus DrmPlugin::getHdcpLevels(
+ ::aidl::android::hardware::drm::HdcpLevels* _aidl_return) {
+ _aidl_return->connectedLevel = HdcpLevel::HDCP_NONE;
+ _aidl_return->maxLevel = HdcpLevel::HDCP_NO_OUTPUT;
+ return toNdkScopedAStatus(Status::OK);
+}
+
+::ndk::ScopedAStatus DrmPlugin::getKeyRequest(
+ const std::vector<uint8_t>& in_scope, const std::vector<uint8_t>& in_initData,
+ const std::string& in_mimeType, ::aidl::android::hardware::drm::KeyType in_keyType,
+ const std::vector<::aidl::android::hardware::drm::KeyValue>& in_optionalParameters,
+ ::aidl::android::hardware::drm::KeyRequest* _aidl_return) {
+ UNUSED(in_optionalParameters);
+
+ KeyRequestType keyRequestType = KeyRequestType::UNKNOWN;
+ std::string defaultUrl("");
+
+ _aidl_return->request = {};
+ _aidl_return->requestType = keyRequestType;
+ _aidl_return->defaultUrl = defaultUrl;
+
+ if (in_scope.size() == 0 ||
+ (in_keyType != KeyType::STREAMING && in_keyType != KeyType::OFFLINE &&
+ in_keyType != KeyType::RELEASE)) {
+ return toNdkScopedAStatus(Status::BAD_VALUE);
+ }
+
+ const std::vector<uint8_t> scopeId = in_scope;
+ ::android::sp<Session> session;
+ if (in_keyType == KeyType::STREAMING || in_keyType == KeyType::OFFLINE) {
+ std::vector<uint8_t> sessionId(scopeId.begin(), scopeId.end());
+ session = mSessionLibrary->findSession(sessionId);
+ if (!session.get()) {
+ return toNdkScopedAStatus(Status::ERROR_DRM_SESSION_NOT_OPENED);
+ } else if (session->getMockError() != clearkeydrm::OK) {
+ return toNdkScopedAStatus(session->getMockError());
+ }
+ keyRequestType = KeyRequestType::INITIAL;
+ }
+
+ std::vector<uint8_t> request = {};
+ auto keyType = static_cast<CdmKeyType>(in_keyType);
+ auto status = session->getKeyRequest(in_initData, in_mimeType, keyType, &request);
+
+ if (in_keyType == KeyType::RELEASE) {
+ std::vector<uint8_t> keySetId(scopeId.begin(), scopeId.end());
+ std::string requestString(request.begin(), request.end());
+ if (requestString.find(kOfflineLicense) != std::string::npos) {
+ std::string emptyResponse;
+ std::string keySetIdString(keySetId.begin(), keySetId.end());
+ if (!mFileHandle.StoreLicense(keySetIdString, DeviceFiles::kLicenseStateReleasing,
+ emptyResponse)) {
+ ALOGE("Problem releasing offline license");
+ return toNdkScopedAStatus(Status::ERROR_DRM_UNKNOWN);
+ }
+ if (mReleaseKeysMap.find(keySetIdString) == mReleaseKeysMap.end()) {
+ ::android::sp<Session> session = mSessionLibrary->createSession();
+ mReleaseKeysMap[keySetIdString] = session->sessionId();
+ } else {
+ ALOGI("key is in use, ignore release request");
+ }
+ } else {
+ ALOGE("Offline license not found, nothing to release");
+ }
+ keyRequestType = KeyRequestType::RELEASE;
+ }
+ _aidl_return->request = request;
+ _aidl_return->requestType = keyRequestType;
+ _aidl_return->defaultUrl = defaultUrl;
+ return toNdkScopedAStatus(status);
+}
+
+::ndk::ScopedAStatus DrmPlugin::getLogMessages(
+ std::vector<::aidl::android::hardware::drm::LogMessage>* _aidl_return) {
+ using std::chrono::duration_cast;
+ using std::chrono::milliseconds;
+ using std::chrono::system_clock;
+
+ auto timeMillis = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
+
+ std::vector<::aidl::android::hardware::drm::LogMessage> logs = {
+ {timeMillis, ::aidl::android::hardware::drm::LogPriority::ERROR,
+ std::string("Not implemented")}};
+ *_aidl_return = logs;
+ return toNdkScopedAStatus(Status::OK);
+}
+
+::ndk::ScopedAStatus DrmPlugin::getMetrics(
+ std::vector<::aidl::android::hardware::drm::DrmMetricGroup>* _aidl_return) {
+ // Set the open session count metric.
+ DrmMetricNamedValue openSessionOkAttribute = {"status", static_cast<int64_t>(Status::OK)};
+ DrmMetricNamedValue openSessionMetricValue = {"count", mOpenSessionOkCount};
+ DrmMetric openSessionMetric = {
+ "open_session", {openSessionOkAttribute}, {openSessionMetricValue}};
+
+ // Set the close session count metric.
+ DrmMetricNamedValue closeSessionOkAttribute = {"status", static_cast<int64_t>(Status::OK)};
+ DrmMetricNamedValue closeSessionMetricValue = {"count", mCloseSessionOkCount};
+ DrmMetric closeSessionMetric = {
+ "close_session", {closeSessionOkAttribute}, {closeSessionMetricValue}};
+
+ // Set the close session, not opened metric.
+ DrmMetricNamedValue closeSessionNotOpenedAttribute = {"status",
+ static_cast<int64_t>(Status::ERROR_DRM_SESSION_NOT_OPENED)};
+ DrmMetricNamedValue closeSessionNotOpenedMetricValue = {"count", mCloseSessionNotOpenedCount};
+ DrmMetric closeSessionNotOpenedMetric = {
+ "close_session", {closeSessionNotOpenedAttribute}, {closeSessionNotOpenedMetricValue}};
+
+ // Set the setPlaybackId metric.
+ std::vector<DrmMetricNamedValue> sids = {};
+ std::vector<DrmMetricNamedValue> playbackIds = {};
+ for (const auto& [key, value] : mPlaybackId) {
+ std::string sid(key.begin(), key.end());
+ DrmMetricNamedValue sessionIdAttribute = {"sid", sid};
+ sids.push_back(sessionIdAttribute);
+
+ DrmMetricNamedValue playbackIdMetricValue = {"playbackId", value};
+ playbackIds.push_back(playbackIdMetricValue);
+ }
+ DrmMetric setPlaybackIdMetric = {"set_playback_id", sids, playbackIds};
+
+ DrmMetricGroup metrics = {{openSessionMetric, closeSessionMetric, closeSessionNotOpenedMetric,
+ setPlaybackIdMetric}};
+
+ *_aidl_return = {metrics};
+ return toNdkScopedAStatus(Status::OK);
+}
+
+::ndk::ScopedAStatus DrmPlugin::getNumberOfSessions(
+ ::aidl::android::hardware::drm::NumberOfSessions* _aidl_return) {
+ _aidl_return->currentSessions = mSessionLibrary->numOpenSessions();
+ _aidl_return->maxSessions = 10;
+ return toNdkScopedAStatus(Status::OK);
+}
+
+::ndk::ScopedAStatus DrmPlugin::getOfflineLicenseKeySetIds(
+ std::vector<::aidl::android::hardware::drm::KeySetId>* _aidl_return) {
+ std::vector<std::string> licenseNames = mFileHandle.ListLicenses();
+ std::vector<KeySetId> keySetIds = {};
+ if (mMockError != Status::OK) {
+ *_aidl_return = keySetIds;
+ return toNdkScopedAStatus(toMockStatus(mMockError));
+ }
+ for (const auto& name : licenseNames) {
+ std::vector<uint8_t> keySetId(name.begin(), name.end());
+ KeySetId id = {};
+ id.keySetId = keySetId;
+ keySetIds.push_back(id);
+ }
+ *_aidl_return = keySetIds;
+ return toNdkScopedAStatus(Status::OK);
+}
+
+::ndk::ScopedAStatus DrmPlugin::getOfflineLicenseState(
+ const ::aidl::android::hardware::drm::KeySetId& in_keySetId,
+ ::aidl::android::hardware::drm::OfflineLicenseState* _aidl_return) {
+ std::string licenseName(in_keySetId.keySetId.begin(), in_keySetId.keySetId.end());
+ DeviceFiles::LicenseState state;
+ std::string license;
+ OfflineLicenseState licenseState = OfflineLicenseState::UNKNOWN;
+ Status status = Status::OK;
+ if (mMockError != Status::OK) {
+ *_aidl_return = licenseState;
+ return toNdkScopedAStatus(toMockStatus(mMockError));
+ } else if (mFileHandle.RetrieveLicense(licenseName, &state, &license)) {
+ switch (state) {
+ case DeviceFiles::kLicenseStateActive:
+ licenseState = OfflineLicenseState::USABLE;
+ break;
+ case DeviceFiles::kLicenseStateReleasing:
+ licenseState = OfflineLicenseState::INACTIVE;
+ break;
+ case DeviceFiles::kLicenseStateUnknown:
+ licenseState = OfflineLicenseState::UNKNOWN;
+ break;
+ }
+ } else {
+ status = Status::BAD_VALUE;
+ }
+ *_aidl_return = licenseState;
+ return toNdkScopedAStatus(status);
+}
+
+::ndk::ScopedAStatus DrmPlugin::getPropertyByteArray(const std::string& in_propertyName,
+ std::vector<uint8_t>* _aidl_return) {
+ std::map<std::string, std::vector<uint8_t>>::iterator itr =
+ mByteArrayProperties.find(std::string(in_propertyName.c_str()));
+ Status status = Status::OK;
+ if (itr != mByteArrayProperties.end()) {
+ *_aidl_return = itr->second;
+ } else {
+ ALOGE("App requested unknown property: %s", in_propertyName.c_str());
+ status = Status::BAD_VALUE;
+ *_aidl_return = {};
+ }
+ return toNdkScopedAStatus(status);
+}
+
+::ndk::ScopedAStatus DrmPlugin::getPropertyString(const std::string& in_propertyName,
+ std::string* _aidl_return) {
+ std::string name(in_propertyName.c_str());
+ std::string value;
+ Status status = Status::OK;
+
+ if (name == kVendorKey) {
+ value = mStringProperties[kVendorKey];
+ } else if (name == kVersionKey) {
+ value = mStringProperties[kVersionKey];
+ } else if (name == kPluginDescriptionKey) {
+ value = mStringProperties[kPluginDescriptionKey];
+ } else if (name == kAlgorithmsKey) {
+ value = mStringProperties[kAlgorithmsKey];
+ } else if (name == kListenerTestSupportKey) {
+ value = mStringProperties[kListenerTestSupportKey];
+ } else if (name == kDrmErrorTestKey) {
+ value = mStringProperties[kDrmErrorTestKey];
+ } else {
+ ALOGE("App requested unknown string property %s", name.c_str());
+ status = Status::ERROR_DRM_CANNOT_HANDLE;
+ }
+ *_aidl_return = value;
+ return toNdkScopedAStatus(status);
+}
+
+::ndk::ScopedAStatus DrmPlugin::getProvisionRequest(
+ const std::string& in_certificateType, const std::string& in_certificateAuthority,
+ ::aidl::android::hardware::drm::ProvisionRequest* _aidl_return) {
+ UNUSED(in_certificateType);
+ UNUSED(in_certificateAuthority);
+ _aidl_return->request = {};
+ _aidl_return->defaultUrl = {};
+ return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
+}
+
+::ndk::ScopedAStatus DrmPlugin::getSecureStop(
+ const ::aidl::android::hardware::drm::SecureStopId& in_secureStopId,
+ ::aidl::android::hardware::drm::SecureStop* _aidl_return) {
+ std::vector<uint8_t> stop = {};
+
+ mSecureStopLock.lock();
+ auto itr = mSecureStops.find(in_secureStopId.secureStopId);
+ if (itr != mSecureStops.end()) {
+ ClearkeySecureStop clearkeyStop = itr->second;
+ stop.assign(clearkeyStop.id.begin(), clearkeyStop.id.end());
+ stop.assign(clearkeyStop.data.begin(), clearkeyStop.data.end());
+ }
+ mSecureStopLock.unlock();
+
+ SecureStop secureStop = {};
+ Status status = Status::OK;
+ if (!stop.empty()) {
+ secureStop.opaqueData = stop;
+ } else {
+ status = Status::BAD_VALUE;
+ }
+ *_aidl_return = secureStop;
+ return toNdkScopedAStatus(status);
+}
+
+::ndk::ScopedAStatus DrmPlugin::getSecureStopIds(
+ std::vector<::aidl::android::hardware::drm::SecureStopId>* _aidl_return) {
+ mSecureStopLock.lock();
+ std::vector<::aidl::android::hardware::drm::SecureStopId> ids;
+ for (auto itr = mSecureStops.begin(); itr != mSecureStops.end(); ++itr) {
+ SecureStopId id;
+ id.secureStopId = itr->first;
+ ids.push_back(id);
+ }
+ mSecureStopLock.unlock();
+
+ *_aidl_return = ids;
+ return toNdkScopedAStatus(Status::OK);
+}
+
+::ndk::ScopedAStatus DrmPlugin::getSecureStops(
+ std::vector<::aidl::android::hardware::drm::SecureStop>* _aidl_return) {
+ mSecureStopLock.lock();
+ std::vector<::aidl::android::hardware::drm::SecureStop> stops;
+ for (auto itr = mSecureStops.begin(); itr != mSecureStops.end(); ++itr) {
+ ClearkeySecureStop clearkeyStop = itr->second;
+ std::vector<uint8_t> stop = {};
+ stop.assign(clearkeyStop.id.begin(), clearkeyStop.id.end());
+ stop.assign(clearkeyStop.data.begin(), clearkeyStop.data.end());
+
+ SecureStop secureStop;
+ secureStop.opaqueData = stop;
+ stops.push_back(secureStop);
+ }
+ mSecureStopLock.unlock();
+
+ *_aidl_return = stops;
+ return toNdkScopedAStatus(Status::OK);
+}
+
+::ndk::ScopedAStatus DrmPlugin::getSecurityLevel(
+ const std::vector<uint8_t>& in_sessionId,
+ ::aidl::android::hardware::drm::SecurityLevel* _aidl_return) {
+ if (in_sessionId.size() == 0) {
+ *_aidl_return = ::aidl::android::hardware::drm::SecurityLevel::UNKNOWN;
+ return toNdkScopedAStatus(Status::BAD_VALUE);
+ }
+
+ std::vector<uint8_t> sid = in_sessionId;
+ ::android::sp<Session> session = mSessionLibrary->findSession(sid);
+ if (!session.get()) {
+ *_aidl_return = SecurityLevel::UNKNOWN;
+ return toNdkScopedAStatus(Status::ERROR_DRM_SESSION_NOT_OPENED);
+ }
+
+ std::map<std::vector<uint8_t>, ::aidl::android::hardware::drm::SecurityLevel>::iterator itr =
+ mSecurityLevel.find(sid);
+ if (itr == mSecurityLevel.end()) {
+ ALOGE("Session id not found");
+ *_aidl_return = SecurityLevel::UNKNOWN;
+ return toNdkScopedAStatus(Status::ERROR_DRM_INVALID_STATE);
+ }
+
+ *_aidl_return = itr->second;
+ return toNdkScopedAStatus(Status::OK);
+}
+
+::ndk::ScopedAStatus DrmPlugin::openSession(
+ ::aidl::android::hardware::drm::SecurityLevel in_securityLevel,
+ std::vector<uint8_t>* _aidl_return) {
+ ::android::sp<Session> session = mSessionLibrary->createSession();
+ processMockError(session);
+ std::vector<uint8_t> sessionId = session->sessionId();
+
+ Status status = setSecurityLevel(sessionId, in_securityLevel);
+ if (status == Status::OK) {
+ mOpenSessionOkCount++;
+ } else {
+ mSessionLibrary->destroySession(session);
+ sessionId.clear();
+ }
+ *_aidl_return = sessionId;
+ return toNdkScopedAStatus(status);
+}
+
+::ndk::ScopedAStatus DrmPlugin::provideKeyResponse(
+ const std::vector<uint8_t>& in_scope, const std::vector<uint8_t>& in_response,
+ ::aidl::android::hardware::drm::KeySetId* _aidl_return) {
+ if (in_scope.size() == 0 || in_response.size() == 0) {
+ // Returns empty keySetId
+ *_aidl_return = {};
+ return toNdkScopedAStatus(Status::BAD_VALUE);
+ }
+
+ std::string responseString(reinterpret_cast<const char*>(in_response.data()),
+ in_response.size());
+ const std::vector<uint8_t> scopeId = in_scope;
+ std::vector<uint8_t> sessionId = {};
+ std::string keySetId;
+
+ bool isOfflineLicense = responseString.find(kOfflineLicense) != std::string::npos;
+ if (scopeId.size() < kKeySetIdPrefix.size()) {
+ android_errorWriteLog(0x534e4554, "144507096");
+ *_aidl_return = {};
+ return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
+ }
+ bool isRelease = (memcmp(scopeId.data(), kKeySetIdPrefix.data(), kKeySetIdPrefix.size()) == 0);
+ if (isRelease) {
+ keySetId.assign(scopeId.begin(), scopeId.end());
+
+ auto iter = mReleaseKeysMap.find(std::string(keySetId.begin(), keySetId.end()));
+ if (iter != mReleaseKeysMap.end()) {
+ sessionId.assign(iter->second.begin(), iter->second.end());
+ }
+ } else {
+ sessionId.assign(scopeId.begin(), scopeId.end());
+ // non offline license returns empty keySetId
+ keySetId.clear();
+ }
+
+ ::android::sp<Session> session = mSessionLibrary->findSession(sessionId);
+ if (!session.get()) {
+ *_aidl_return = {};
+ return toNdkScopedAStatus(Status::ERROR_DRM_SESSION_NOT_OPENED);
+ }
+ setPlayPolicy();
+
+ auto res = session->provideKeyResponse(in_response);
+ if (res == clearkeydrm::OK) {
+ if (isOfflineLicense) {
+ if (isRelease) {
+ mFileHandle.DeleteLicense(keySetId);
+ mSessionLibrary->destroySession(session);
+ } else {
+ if (!makeKeySetId(&keySetId)) {
+ *_aidl_return = {};
+ return toNdkScopedAStatus(Status::ERROR_DRM_UNKNOWN);
+ }
+
+ bool ok = mFileHandle.StoreLicense(
+ keySetId, DeviceFiles::kLicenseStateActive,
+ std::string(in_response.begin(), in_response.end()));
+ if (!ok) {
+ ALOGE("Failed to store offline license");
+ }
+ }
+ }
+
+ // Test calling AMediaDrm listeners.
+ sendEvent(EventType::VENDOR_DEFINED, sessionId, sessionId);
+
+ sendExpirationUpdate(sessionId, 100);
+
+ std::vector<KeyStatus> keysStatus = {};
+ KeyStatus keyStatus;
+
+ std::vector<uint8_t> keyId1 = {0xA, 0xB, 0xC};
+ keyStatus.keyId = keyId1;
+ keyStatus.type = KeyStatusType::USABLE;
+ keysStatus.push_back(keyStatus);
+
+ std::vector<uint8_t> keyId2 = {0xD, 0xE, 0xF};
+ keyStatus.keyId = keyId2;
+ keyStatus.type = KeyStatusType::EXPIRED;
+ keysStatus.push_back(keyStatus);
+
+ std::vector<uint8_t> keyId3 = {0x0, 0x1, 0x2};
+ keyStatus.keyId = keyId3;
+ keyStatus.type = KeyStatusType::USABLEINFUTURE;
+ keysStatus.push_back(keyStatus);
+
+ sendKeysChange(sessionId, keysStatus, true);
+
+ installSecureStop(sessionId);
+ } else {
+ ALOGE("provideKeyResponse returns error=%d", res);
+ }
+
+ std::vector<uint8_t> keySetIdVec(keySetId.begin(), keySetId.end());
+ _aidl_return->keySetId = keySetIdVec;
+ return toNdkScopedAStatus(res);
+}
+
+::ndk::ScopedAStatus DrmPlugin::provideProvisionResponse(
+ const std::vector<uint8_t>& in_response,
+ ::aidl::android::hardware::drm::ProvideProvisionResponseResult* _aidl_return) {
+ Status status = Status::ERROR_DRM_CANNOT_HANDLE;
+ _aidl_return->certificate = {};
+ _aidl_return->wrappedKey = {};
+ if (in_response.size() == 0) {
+ status = Status::BAD_VALUE;
+ }
+ return toNdkScopedAStatus(status);
+}
+
+::ndk::ScopedAStatus DrmPlugin::queryKeyStatus(
+ const std::vector<uint8_t>& in_sessionId,
+ std::vector<::aidl::android::hardware::drm::KeyValue>* _aidl_return) {
+ if (in_sessionId.size() == 0) {
+ // Returns empty key status KeyValue pair
+ *_aidl_return = {};
+ return toNdkScopedAStatus(Status::BAD_VALUE);
+ }
+
+ std::vector<KeyValue> infoMap = {};
+ mPlayPolicyLock.lock();
+ KeyValue keyValuePair;
+ for (size_t i = 0; i < mPlayPolicy.size(); ++i) {
+ keyValuePair.key = mPlayPolicy[i].key;
+ keyValuePair.value = mPlayPolicy[i].value;
+ infoMap.push_back(keyValuePair);
+ }
+ mPlayPolicyLock.unlock();
+ *_aidl_return = infoMap;
+ return toNdkScopedAStatus(Status::OK);
+}
+
+::ndk::ScopedAStatus DrmPlugin::releaseAllSecureStops() {
+ Status status = Status::OK;
+ const auto res = removeAllSecureStops();
+ if (!res.isOk() && res.getExceptionCode() == EX_SERVICE_SPECIFIC) {
+ status = static_cast<Status>(res.getServiceSpecificError());
+ }
+ return toNdkScopedAStatus(status);
+}
+
+::ndk::ScopedAStatus DrmPlugin::releaseSecureStop(
+ const ::aidl::android::hardware::drm::SecureStopId& in_secureStopId) {
+ Status status = Status::OK;
+ const auto res = removeSecureStop(in_secureStopId);
+ if (!res.isOk() && res.getExceptionCode() == EX_SERVICE_SPECIFIC) {
+ status = static_cast<Status>(res.getServiceSpecificError());
+ }
+ return toNdkScopedAStatus(status);
+}
+
+::ndk::ScopedAStatus DrmPlugin::releaseSecureStops(
+ const ::aidl::android::hardware::drm::OpaqueData& in_ssRelease) {
+ // OpaqueData starts with 4 byte decimal integer string
+ const size_t kFourBytesOffset = 4;
+ if (in_ssRelease.opaqueData.size() < kFourBytesOffset) {
+ ALOGE("Invalid secureStopRelease length");
+ return toNdkScopedAStatus(Status::BAD_VALUE);
+ }
+
+ Status status = Status::OK;
+ std::vector<uint8_t> input = in_ssRelease.opaqueData;
+
+ if (input.size() < kSecureStopIdSize + kFourBytesOffset) {
+ // The minimum size of secure stop has to contain
+ // a 4 bytes count and one secureStop id
+ ALOGE("Total size of secureStops is too short");
+ return toNdkScopedAStatus(Status::BAD_VALUE);
+ }
+
+ // The format of opaqueData is shared between the server
+ // and the drm service. The clearkey implementation consists of:
+ // count - number of secure stops
+ // list of fixed length secure stops
+ size_t countBufferSize = sizeof(uint32_t);
+ if (input.size() < countBufferSize) {
+ // SafetyNet logging
+ android_errorWriteLog(0x534e4554, "144766455");
+ return toNdkScopedAStatus(Status::BAD_VALUE);
+ }
+ uint32_t count = 0;
+ sscanf(reinterpret_cast<char*>(input.data()), "%04" PRIu32, &count);
+
+ // Avoid divide by 0 below.
+ if (count == 0) {
+ ALOGE("Invalid 0 secureStop count");
+ return toNdkScopedAStatus(Status::BAD_VALUE);
+ }
+
+ // Computes the fixed length secureStop size
+ size_t secureStopSize = (input.size() - kFourBytesOffset) / count;
+ if (secureStopSize < kSecureStopIdSize) {
+ // A valid secureStop contains the id plus data
+ ALOGE("Invalid secureStop size");
+ return toNdkScopedAStatus(Status::BAD_VALUE);
+ }
+ uint8_t* buffer = new uint8_t[secureStopSize];
+ size_t offset = kFourBytesOffset; // skip the count
+ for (size_t i = 0; i < count; ++i, offset += secureStopSize) {
+ memcpy(buffer, input.data() + offset, secureStopSize);
+
+ // A secureStop contains id+data, we only use the id for removal
+ std::vector<uint8_t> id(buffer, buffer + kSecureStopIdSize);
+ ::aidl::android::hardware::drm::SecureStopId secureStopId{id};
+ const auto res = removeSecureStop(secureStopId);
+ if (!res.isOk() && res.getExceptionCode() == EX_SERVICE_SPECIFIC) {
+ status = static_cast<Status>(res.getServiceSpecificError());
+ }
+ if (Status::OK != status) break;
+ }
+
+ delete[] buffer;
+ return toNdkScopedAStatus(status);
+}
+
+::ndk::ScopedAStatus DrmPlugin::removeAllSecureStops() {
+ Mutex::Autolock lock(mSecureStopLock);
+
+ mSecureStops.clear();
+ mNextSecureStopId = kSecureStopIdStart;
+ return toNdkScopedAStatus(Status::OK);
+}
+
+::ndk::ScopedAStatus DrmPlugin::removeKeys(const std::vector<uint8_t>& in_sessionId) {
+ Status status = Status::ERROR_DRM_CANNOT_HANDLE;
+ if (in_sessionId.size() == 0) {
+ status = Status::BAD_VALUE;
+ }
+ return toNdkScopedAStatus(status);
+}
+
+::ndk::ScopedAStatus DrmPlugin::removeOfflineLicense(
+ const ::aidl::android::hardware::drm::KeySetId& in_keySetId) {
+ if (mMockError != Status::OK) {
+ return toNdkScopedAStatus(toMockStatus(mMockError));
+ }
+ Status status = Status::BAD_VALUE;
+ std::string licenseName(in_keySetId.keySetId.begin(), in_keySetId.keySetId.end());
+ if (mFileHandle.DeleteLicense(licenseName)) {
+ status = Status::OK;
+ }
+ return toNdkScopedAStatus(status);
+}
+
+::ndk::ScopedAStatus DrmPlugin::removeSecureStop(
+ const ::aidl::android::hardware::drm::SecureStopId& in_secureStopId) {
+ Mutex::Autolock lock(mSecureStopLock);
+
+ Status status = Status::OK;
+ if (1 != mSecureStops.erase(in_secureStopId.secureStopId)) {
+ status = Status::BAD_VALUE;
+ }
+ return toNdkScopedAStatus(status);
+}
+
+::ndk::ScopedAStatus DrmPlugin::requiresSecureDecoder(
+ const std::string& in_mime, ::aidl::android::hardware::drm::SecurityLevel in_level,
+ bool* _aidl_return) {
+ UNUSED(in_mime);
+ UNUSED(in_level);
+ *_aidl_return = false;
+ return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus DrmPlugin::requiresSecureDecoderDefault(const std::string& in_mime,
+ bool* _aidl_return) {
+ UNUSED(in_mime);
+ // Clearkey only supports SW_SECURE_CRYPTO, so we always returns false
+ // regardless of mime type.
+ *_aidl_return = false;
+ return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus DrmPlugin::restoreKeys(
+ const std::vector<uint8_t>& in_sessionId,
+ const ::aidl::android::hardware::drm::KeySetId& in_keySetId) {
+ if (in_sessionId.size() == 0 || in_keySetId.keySetId.size() == 0) {
+ return toNdkScopedAStatus(Status::BAD_VALUE);
+ }
+
+ DeviceFiles::LicenseState licenseState;
+ std::string offlineLicense;
+ if (!mFileHandle.RetrieveLicense(
+ std::string(in_keySetId.keySetId.begin(), in_keySetId.keySetId.end()),
+ &licenseState, &offlineLicense)) {
+ ALOGE("Failed to restore offline license");
+ return toNdkScopedAStatus(Status::ERROR_DRM_NO_LICENSE);
+ }
+
+ if (DeviceFiles::kLicenseStateUnknown == licenseState ||
+ DeviceFiles::kLicenseStateReleasing == licenseState) {
+ ALOGE("Invalid license state=%d", licenseState);
+ return toNdkScopedAStatus(Status::ERROR_DRM_NO_LICENSE);
+ }
+
+ ::android::sp<Session> session = mSessionLibrary->findSession(in_sessionId);
+ if (!session.get()) {
+ return toNdkScopedAStatus(Status::ERROR_DRM_SESSION_NOT_OPENED);
+ }
+ auto res = session->provideKeyResponse(
+ std::vector<uint8_t>(offlineLicense.begin(), offlineLicense.end()));
+ if (res != clearkeydrm::OK) {
+ ALOGE("Failed to restore keys");
+ }
+ return toNdkScopedAStatus(res);
+}
+
+void DrmPlugin::sendEvent(::aidl::android::hardware::drm::EventType in_eventType,
+ const std::vector<uint8_t>& in_sessionId,
+ const std::vector<uint8_t>& in_data) {
+ if (mListener != nullptr) {
+ mListener->onEvent(in_eventType, in_sessionId, in_data);
+ } else {
+ ALOGE("Null event listener, event not sent");
+ }
+ return;
+}
+
+void DrmPlugin::sendExpirationUpdate(const std::vector<uint8_t>& in_sessionId,
+ int64_t in_expiryTimeInMS) {
+ if (mListener != nullptr) {
+ mListener->onExpirationUpdate(in_sessionId, in_expiryTimeInMS);
+ } else {
+ ALOGE("Null event listener, event not sent");
+ }
+ return;
+}
+
+void DrmPlugin::sendKeysChange(
+ const std::vector<uint8_t>& in_sessionId,
+ const std::vector<::aidl::android::hardware::drm::KeyStatus>& in_keyStatusList,
+ bool in_hasNewUsableKey) {
+ if (mListener != nullptr) {
+ mListener->onKeysChange(in_sessionId, in_keyStatusList, in_hasNewUsableKey);
+ } else {
+ ALOGE("Null event listener, event not sent");
+ }
+ return;
+}
+
+void DrmPlugin::sendSessionLostState(const std::vector<uint8_t>& in_sessionId) {
+ if (mListener != nullptr) {
+ mListener->onSessionLostState(in_sessionId);
+ }
+ return;
+}
+
+::ndk::ScopedAStatus DrmPlugin::setCipherAlgorithm(const std::vector<uint8_t>& /*in_sessionId*/,
+ const std::string& /*in_algorithm*/) {
+ return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
+}
+
+::ndk::ScopedAStatus DrmPlugin::setListener(
+ const std::shared_ptr<
+ ::aidl::android::hardware::drm::IDrmPluginListener>& in_listener) {
+ mListener = in_listener;
+ return toNdkScopedAStatus(Status::OK);
+}
+
+::ndk::ScopedAStatus DrmPlugin::setMacAlgorithm(const std::vector<uint8_t>& /*in_sessionId*/,
+ const std::string& /*in_algorithm*/) {
+ return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
+}
+
+::ndk::ScopedAStatus DrmPlugin::setPlaybackId(const std::vector<uint8_t>& in_sessionId,
+ const std::string& in_playbackId) {
+ if (in_sessionId.size() == 0) {
+ ALOGE("Invalid empty session id");
+ return toNdkScopedAStatus(Status::BAD_VALUE);
+ }
+
+ std::vector<uint8_t> sid = in_sessionId;
+ mPlaybackId[sid] = in_playbackId;
+ return toNdkScopedAStatus(Status::OK);
+}
+
+::ndk::ScopedAStatus DrmPlugin::setPropertyByteArray(const std::string& in_propertyName,
+ const std::vector<uint8_t>& in_value) {
+ if (in_propertyName == kDeviceIdKey) {
+ ALOGD("Cannot set immutable property: %s", in_propertyName.c_str());
+ return toNdkScopedAStatus(Status::BAD_VALUE);
+ } else if (in_propertyName == kClientIdKey) {
+ mByteArrayProperties[kClientIdKey] = in_value;
+ return toNdkScopedAStatus(Status::OK);
+ }
+
+ // Setting of undefined properties is not supported
+ ALOGE("Failed to set property byte array, key=%s", in_propertyName.c_str());
+ return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
+}
+
+::ndk::ScopedAStatus DrmPlugin::setPropertyString(const std::string& in_propertyName,
+ const std::string& in_value) {
+ std::string immutableKeys;
+ immutableKeys.append(kAlgorithmsKey + ",");
+ immutableKeys.append(kPluginDescriptionKey + ",");
+ immutableKeys.append(kVendorKey + ",");
+ immutableKeys.append(kVersionKey + ",");
+
+ std::string key = std::string(in_propertyName.c_str());
+ if (immutableKeys.find(key) != std::string::npos) {
+ ALOGD("Cannot set immutable property: %s", key.c_str());
+ return toNdkScopedAStatus(Status::BAD_VALUE);
+ }
+
+ std::map<std::string, std::string>::iterator itr = mStringProperties.find(key);
+ if (itr == mStringProperties.end()) {
+ ALOGE("Cannot set undefined property string, key=%s", key.c_str());
+ return toNdkScopedAStatus(Status::BAD_VALUE);
+ }
+
+ if (in_propertyName == kDrmErrorTestKey) {
+ if (in_value == kResourceContentionValue) {
+ mMockError = Status::ERROR_DRM_RESOURCE_CONTENTION;
+ } else if (in_value == kLostStateValue) {
+ mMockError = Status::ERROR_DRM_SESSION_LOST_STATE;
+ } else if (in_value == kFrameTooLargeValue) {
+ mMockError = Status::ERROR_DRM_FRAME_TOO_LARGE;
+ } else if (in_value == kInvalidStateValue) {
+ mMockError = Status::ERROR_DRM_INVALID_STATE;
+ } else {
+ mMockError = Status::ERROR_DRM_UNKNOWN;
+ }
+ }
+
+ mStringProperties[key] = std::string(in_value.c_str());
+ return toNdkScopedAStatus(Status::OK);
+}
+
+::ndk::ScopedAStatus DrmPlugin::sign(const std::vector<uint8_t>& /*in_sessionId*/,
+ const std::vector<uint8_t>& /*in_keyId*/,
+ const std::vector<uint8_t>& /*in_message*/,
+ std::vector<uint8_t>* _aidl_return) {
+ *_aidl_return = {};
+ return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
+}
+
+::ndk::ScopedAStatus DrmPlugin::signRSA(const std::vector<uint8_t>& /*in_sessionId*/,
+ const std::string& /*in_algorithm*/,
+ const std::vector<uint8_t>& /*in_message*/,
+ const std::vector<uint8_t>& /*in_wrappedkey*/,
+ std::vector<uint8_t>* _aidl_return) {
+ *_aidl_return = {};
+ return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
+}
+
+::ndk::ScopedAStatus DrmPlugin::verify(const std::vector<uint8_t>& /*in_sessionId*/,
+ const std::vector<uint8_t>& /*in_keyId*/,
+ const std::vector<uint8_t>& /*in_message*/,
+ const std::vector<uint8_t>& /*in_signature*/,
+ bool* _aidl_return) {
+ *_aidl_return = false;
+ return toNdkScopedAStatus(Status::ERROR_DRM_CANNOT_HANDLE);
+}
+
+// Private methods below.
+void DrmPlugin::setPlayPolicy() {
+ ::android::Mutex::Autolock lock(mPlayPolicyLock);
+ mPlayPolicy.clear();
+
+ KeyValue policy;
+ policy.key = kQueryKeyLicenseType;
+ policy.value = kStreaming;
+ mPlayPolicy.push_back(policy);
+
+ policy.key = kQueryKeyPlayAllowed;
+ policy.value = kTrue;
+ mPlayPolicy.push_back(policy);
+
+ policy.key = kQueryKeyRenewAllowed;
+ mPlayPolicy.push_back(policy);
+}
+
+bool DrmPlugin::makeKeySetId(std::string* keySetId) {
+ if (!keySetId) {
+ ALOGE("keySetId destination not provided");
+ return false;
+ }
+ std::vector<uint8_t> ksid(kKeySetIdPrefix.begin(), kKeySetIdPrefix.end());
+ ksid.resize(kKeySetIdLength);
+ std::vector<uint8_t> randomData((kKeySetIdLength - kKeySetIdPrefix.size()) / 2, 0);
+
+ while (keySetId->empty()) {
+ for (auto itr = randomData.begin(); itr != randomData.end(); ++itr) {
+ *itr = std::rand() % 0xff;
+ }
+ auto id = reinterpret_cast<const uint8_t*>(randomData.data());
+ *keySetId = kKeySetIdPrefix + ::android::ByteArrayToHexString(id, randomData.size());
+ if (mFileHandle.LicenseExists(*keySetId)) {
+ // collision, regenerate
+ ALOGV("Retry generating KeySetId");
+ keySetId->clear();
+ }
+ }
+ return true;
+}
+
+Status DrmPlugin::setSecurityLevel(const std::vector<uint8_t>& sessionId, SecurityLevel level) {
+ if (sessionId.size() == 0) {
+ ALOGE("Invalid empty session id");
+ return Status::BAD_VALUE;
+ }
+
+ if (level != SecurityLevel::DEFAULT && level != SecurityLevel::SW_SECURE_CRYPTO) {
+ ALOGE("Cannot set security level > max");
+ return Status::ERROR_DRM_CANNOT_HANDLE;
+ }
+
+ std::vector<uint8_t> sid = sessionId;
+ ::android::sp<Session> session = mSessionLibrary->findSession(sid);
+ if (!session.get()) {
+ return Status::ERROR_DRM_SESSION_NOT_OPENED;
+ }
+
+ std::map<std::vector<uint8_t>, SecurityLevel>::iterator itr = mSecurityLevel.find(sid);
+ if (itr != mSecurityLevel.end()) {
+ mSecurityLevel[sid] = level;
+ } else {
+ if (!mSecurityLevel.insert(std::pair<std::vector<uint8_t>, SecurityLevel>(sid, level))
+ .second) {
+ ALOGE("Failed to set security level");
+ return Status::ERROR_DRM_INVALID_STATE;
+ }
+ }
+ return Status::OK;
+}
+
+} // namespace clearkey
+} // namespace drm
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/drm/mediadrm/plugins/clearkey/aidl/Service.cpp b/drm/mediadrm/plugins/clearkey/aidl/Service.cpp
new file mode 100644
index 0000000..7d342f3
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/aidl/Service.cpp
@@ -0,0 +1,52 @@
+/*
+ * 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 1
+#define LOG_TAG "clearkey-main"
+
+#include "CreatePluginFactories.h"
+
+#include <android-base/logging.h>
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using ::android::base::InitLogging;
+using ::android::base::LogdLogger;
+
+using ::aidl::android::hardware::drm::clearkey::createCryptoFactory;
+using ::aidl::android::hardware::drm::clearkey::createDrmFactory;
+using ::aidl::android::hardware::drm::clearkey::CryptoFactory;
+using ::aidl::android::hardware::drm::clearkey::DrmFactory;
+
+int main(int /*argc*/, char* argv[]) {
+ InitLogging(argv, LogdLogger());
+ ::android::base::SetMinimumLogSeverity(::android::base::VERBOSE);
+ ABinderProcess_setThreadPoolMaxThreadCount(8);
+
+ std::shared_ptr<DrmFactory> drmFactory = createDrmFactory();
+ const std::string drmInstance = std::string() + DrmFactory::descriptor + "/clearkey";
+ binder_status_t status =
+ AServiceManager_addService(drmFactory->asBinder().get(), drmInstance.c_str());
+ CHECK(status == STATUS_OK);
+
+ std::shared_ptr<CryptoFactory> cryptoFactory = createCryptoFactory();
+ const std::string cryptoInstance = std::string() + CryptoFactory::descriptor + "/clearkey";
+ status = AServiceManager_addService(cryptoFactory->asBinder().get(), cryptoInstance.c_str());
+ CHECK(status == STATUS_OK);
+
+ ABinderProcess_joinThreadPool();
+ return EXIT_FAILURE; // should not reached
+}
diff --git a/drm/mediadrm/plugins/clearkey/aidl/ServiceLazy.cpp b/drm/mediadrm/plugins/clearkey/aidl/ServiceLazy.cpp
new file mode 100644
index 0000000..55aa6e0
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/aidl/ServiceLazy.cpp
@@ -0,0 +1,54 @@
+/*
+ * 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 1
+#define LOG_TAG "clearkey-main"
+
+#include "CreatePluginFactories.h"
+
+#include <android-base/logging.h>
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using ::android::base::InitLogging;
+using ::android::base::StderrLogger;
+
+using ::aidl::android::hardware::drm::clearkey::createCryptoFactory;
+using ::aidl::android::hardware::drm::clearkey::createDrmFactory;
+using ::aidl::android::hardware::drm::clearkey::CryptoFactory;
+using ::aidl::android::hardware::drm::clearkey::DrmFactory;
+
+int main(int /*argc*/, char* argv[]) {
+ InitLogging(argv, StderrLogger);
+ ::android::base::SetMinimumLogSeverity(::android::base::VERBOSE);
+ ABinderProcess_setThreadPoolMaxThreadCount(8);
+
+ binder_status_t status{};
+ std::shared_ptr<DrmFactory> drmFactory = createDrmFactory();
+ const std::string drmInstance = std::string() + DrmFactory::descriptor + "/clearkey";
+ status = AServiceManager_registerLazyService(drmFactory->asBinder().get(),
+ drmInstance.c_str());
+ CHECK(status == STATUS_OK);
+
+ std::shared_ptr<CryptoFactory> cryptoFactory = createCryptoFactory();
+ const std::string cryptoInstance = std::string() + CryptoFactory::descriptor + "/clearkey";
+ status = AServiceManager_registerLazyService(cryptoFactory->asBinder().get(),
+ cryptoInstance.c_str());
+ CHECK(status == STATUS_OK);
+
+ ABinderProcess_joinThreadPool();
+ return EXIT_FAILURE; // should not reached
+}
diff --git a/drm/mediadrm/plugins/clearkey/aidl/android.hardware.drm-service-lazy.clearkey.rc b/drm/mediadrm/plugins/clearkey/aidl/android.hardware.drm-service-lazy.clearkey.rc
new file mode 100644
index 0000000..019c726
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/aidl/android.hardware.drm-service-lazy.clearkey.rc
@@ -0,0 +1,9 @@
+service vendor.drm-clearkey-service /vendor/bin/hw/android.hardware.drm-service.clearkey
+ disabled
+ class hal
+ user media
+ group mediadrm drmrpc
+ ioprio rt 4
+ task_profiles ProcessCapacityHigh
+ interface aidl android.hardware.drm.IDrmFactory/clearkey
+ interface aidl android.hardware.drm.ICryptoFactory/clearkey
diff --git a/drm/mediadrm/plugins/clearkey/aidl/android.hardware.drm-service.clearkey.rc b/drm/mediadrm/plugins/clearkey/aidl/android.hardware.drm-service.clearkey.rc
new file mode 100644
index 0000000..2b2637f
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/aidl/android.hardware.drm-service.clearkey.rc
@@ -0,0 +1,8 @@
+service vendor.drm-clearkey-service /vendor/bin/hw/android.hardware.drm-service.clearkey
+ class hal
+ user media
+ group mediadrm drmrpc
+ ioprio rt 4
+ task_profiles ProcessCapacityHigh
+ interface aidl android.hardware.drm.IDrmFactory/clearkey
+ interface aidl android.hardware.drm.ICryptoFactory/clearkey
diff --git a/drm/mediadrm/plugins/clearkey/aidl/android.hardware.drm-service.clearkey.xml b/drm/mediadrm/plugins/clearkey/aidl/android.hardware.drm-service.clearkey.xml
new file mode 100644
index 0000000..73c15f3
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/aidl/android.hardware.drm-service.clearkey.xml
@@ -0,0 +1,8 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.drm</name>
+ <version>1</version>
+ <fqname>ICryptoFactory/clearkey</fqname>
+ <fqname>IDrmFactory/clearkey</fqname>
+ </hal>
+</manifest>
diff --git a/drm/mediadrm/plugins/clearkey/aidl/include/AidlUtils.h b/drm/mediadrm/plugins/clearkey/aidl/include/AidlUtils.h
new file mode 100644
index 0000000..0370ebe
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/aidl/include/AidlUtils.h
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include <android/binder_auto_utils.h>
+#include "aidl/android/hardware/drm/Status.h"
+#include "ClearKeyTypes.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace drm {
+namespace clearkey {
+
+inline ::aidl::android::hardware::drm::Status toMockStatus(
+ ::aidl::android::hardware::drm::Status status) {
+ switch (status) {
+ case ::aidl::android::hardware::drm::Status::ERROR_DRM_INSUFFICIENT_SECURITY:
+ case ::aidl::android::hardware::drm::Status::ERROR_DRM_FRAME_TOO_LARGE:
+ case ::aidl::android::hardware::drm::Status::ERROR_DRM_SESSION_LOST_STATE:
+ return ::aidl::android::hardware::drm::Status::ERROR_DRM_UNKNOWN;
+ default:
+ return status;
+ }
+}
+
+inline ::ndk::ScopedAStatus toNdkScopedAStatus(::aidl::android::hardware::drm::Status status) {
+ if (Status::OK == status) {
+ return ::ndk::ScopedAStatus::ok();
+ } else {
+ return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(status));
+ }
+}
+
+inline ::ndk::ScopedAStatus toNdkScopedAStatus(clearkeydrm::CdmResponseType res) {
+ return toNdkScopedAStatus(static_cast<::aidl::android::hardware::drm::Status>(res));
+}
+
+#define UNUSED(x) (void)(x);
+
+} // namespace clearkey
+} // namespace drm
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/drm/mediadrm/plugins/clearkey/aidl/include/CreatePluginFactories.h b/drm/mediadrm/plugins/clearkey/aidl/include/CreatePluginFactories.h
new file mode 100644
index 0000000..5a90fb8
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/aidl/include/CreatePluginFactories.h
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include "CryptoFactory.h"
+#include "DrmFactory.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace drm {
+namespace clearkey {
+//extern "C" {
+std::shared_ptr<DrmFactory> createDrmFactory();
+std::shared_ptr<CryptoFactory> createCryptoFactory();
+//}
+
+} // namespace clearkey
+} // namespace drm
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/drm/mediadrm/plugins/clearkey/aidl/include/CryptoFactory.h b/drm/mediadrm/plugins/clearkey/aidl/include/CryptoFactory.h
new file mode 100644
index 0000000..0d6c4ce
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/aidl/include/CryptoFactory.h
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <aidl/android/hardware/drm/BnCryptoFactory.h>
+#include <aidl/android/hardware/drm/ICryptoFactory.h>
+#include <aidl/android/hardware/drm/ICryptoPlugin.h>
+
+#include "ClearKeyTypes.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace drm {
+namespace clearkey {
+
+struct CryptoFactory : public BnCryptoFactory {
+ CryptoFactory() {}
+ virtual ~CryptoFactory() {}
+
+ ::ndk::ScopedAStatus createPlugin(
+ const ::aidl::android::hardware::drm::Uuid& in_uuid,
+ const std::vector<uint8_t>& in_initData,
+ std::shared_ptr<::aidl::android::hardware::drm::ICryptoPlugin>* _aidl_return) override;
+
+ ::ndk::ScopedAStatus isCryptoSchemeSupported(
+ const ::aidl::android::hardware::drm::Uuid& in_uuid, bool* _aidl_return) override;
+
+ private:
+ CLEARKEY_DISALLOW_COPY_AND_ASSIGN(CryptoFactory);
+};
+
+} // namespace clearkey
+} // namespace drm
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/drm/mediadrm/plugins/clearkey/aidl/include/CryptoPlugin.h b/drm/mediadrm/plugins/clearkey/aidl/include/CryptoPlugin.h
new file mode 100644
index 0000000..f98829d
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/aidl/include/CryptoPlugin.h
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <aidl/android/hardware/drm/BnCryptoPlugin.h>
+#include <aidl/android/hardware/drm/Status.h>
+
+#include <aidl/android/hardware/common/Ashmem.h>
+
+#include <android/binder_auto_utils.h>
+
+#include <memory>
+#include <mutex>
+
+#include "ClearKeyTypes.h"
+#include "Session.h"
+
+namespace {
+static const size_t KEY_ID_SIZE = 16;
+static const size_t KEY_IV_SIZE = 16;
+} // namespace
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace drm {
+namespace clearkey {
+
+using namespace clearkeydrm;
+using ::aidl::android::hardware::drm::Status;
+
+struct SharedBufferBase {
+ uint8_t* mBase;
+ int64_t mSize;
+ SharedBufferBase(const ::aidl::android::hardware::common::Ashmem& mem);
+ ~SharedBufferBase();
+};
+
+struct CryptoPlugin : public BnCryptoPlugin {
+ explicit CryptoPlugin(const std::vector<uint8_t>& sessionId) {
+ const auto res = setMediaDrmSession(sessionId);
+ mInitStatus = Status::OK;
+ if (!res.isOk() && res.getExceptionCode() == EX_SERVICE_SPECIFIC) {
+ mInitStatus = static_cast<Status>(res.getServiceSpecificError());
+ }
+ }
+ virtual ~CryptoPlugin() {}
+
+ ::ndk::ScopedAStatus decrypt(
+ bool in_secure, const std::vector<uint8_t>& in_keyId, const std::vector<uint8_t>& in_iv,
+ ::aidl::android::hardware::drm::Mode in_mode,
+ const ::aidl::android::hardware::drm::Pattern& in_pattern,
+ const std::vector<::aidl::android::hardware::drm::SubSample>& in_subSamples,
+ const ::aidl::android::hardware::drm::SharedBuffer& in_source, int64_t in_offset,
+ const ::aidl::android::hardware::drm::DestinationBuffer& in_destination,
+ ::aidl::android::hardware::drm::DecryptResult* _aidl_return) override;
+
+ ::ndk::ScopedAStatus getLogMessages(
+ std::vector<::aidl::android::hardware::drm::LogMessage>* _aidl_return) override;
+
+ ::ndk::ScopedAStatus notifyResolution(int32_t in_width, int32_t in_height) override;
+
+ ::ndk::ScopedAStatus requiresSecureDecoderComponent(const std::string& in_mime,
+ bool* _aidl_return) override;
+
+ ::ndk::ScopedAStatus setMediaDrmSession(const std::vector<uint8_t>& in_sessionId) override;
+
+ ::ndk::ScopedAStatus setSharedBufferBase(
+ const ::aidl::android::hardware::common::Ashmem& in_base, int32_t in_bufferId) override;
+
+ ::aidl::android::hardware::drm::Status getInitStatus() const { return mInitStatus; }
+
+ private:
+ CLEARKEY_DISALLOW_COPY_AND_ASSIGN(CryptoPlugin);
+
+ std::mutex mSharedBufferLock;
+ std::map<uint32_t, std::shared_ptr<SharedBufferBase>> mSharedBufferMap
+ GUARDED_BY(mSharedBufferLock);
+ ::android::sp<Session> mSession;
+ ::aidl::android::hardware::drm::Status mInitStatus;
+};
+
+} // namespace clearkey
+} // namespace drm
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/drm/mediadrm/plugins/clearkey/aidl/include/DrmFactory.h b/drm/mediadrm/plugins/clearkey/aidl/include/DrmFactory.h
new file mode 100644
index 0000000..0143dc7
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/aidl/include/DrmFactory.h
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <aidl/android/hardware/drm/BnDrmFactory.h>
+#include <aidl/android/hardware/drm/IDrmFactory.h>
+#include <aidl/android/hardware/drm/IDrmPlugin.h>
+
+#include <string>
+#include <vector>
+
+#include "ClearKeyTypes.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace drm {
+namespace clearkey {
+
+struct DrmFactory : public BnDrmFactory {
+ DrmFactory() {}
+ virtual ~DrmFactory() {}
+
+ ::ndk::ScopedAStatus createPlugin(
+ const ::aidl::android::hardware::drm::Uuid& in_uuid,
+ const std::string& in_appPackageName,
+ std::shared_ptr<::aidl::android::hardware::drm::IDrmPlugin>* _aidl_return) override;
+
+ ::ndk::ScopedAStatus getSupportedCryptoSchemes(
+ std::vector<::aidl::android::hardware::drm::Uuid>* _aidl_return) override;
+
+ ::ndk::ScopedAStatus isContentTypeSupported(const std::string& in_mimeType,
+ bool* _aidl_return) override;
+
+ ::ndk::ScopedAStatus isCryptoSchemeSupported(
+ const ::aidl::android::hardware::drm::Uuid& in_uuid, const std::string& in_mimeType,
+ ::aidl::android::hardware::drm::SecurityLevel in_securityLevel,
+ bool* _aidl_return) override;
+
+ binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
+
+
+ private:
+ CLEARKEY_DISALLOW_COPY_AND_ASSIGN(DrmFactory);
+};
+
+} // namespace clearkey
+} // namespace drm
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/drm/mediadrm/plugins/clearkey/aidl/include/DrmPlugin.h b/drm/mediadrm/plugins/clearkey/aidl/include/DrmPlugin.h
new file mode 100644
index 0000000..44db1d5
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/aidl/include/DrmPlugin.h
@@ -0,0 +1,214 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <aidl/android/hardware/drm/BnDrmPlugin.h>
+#include <aidl/android/hardware/drm/IDrmPluginListener.h>
+#include <aidl/android/hardware/drm/Status.h>
+
+#include <stdio.h>
+#include <map>
+
+#include <utils/List.h>
+
+#include "DeviceFiles.h"
+#include "SessionLibrary.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace drm {
+namespace clearkey {
+
+using namespace clearkeydrm;
+using ::aidl::android::hardware::drm::KeyType;
+using ::aidl::android::hardware::drm::Status;
+
+struct DrmPlugin : public BnDrmPlugin {
+ public:
+ explicit DrmPlugin(SessionLibrary* sessionLibrary);
+ virtual ~DrmPlugin() { mFileHandle.DeleteAllLicenses(); }
+
+ ::ndk::ScopedAStatus closeSession(const std::vector<uint8_t>& in_sessionId) override;
+ ::ndk::ScopedAStatus decrypt(const std::vector<uint8_t>& in_sessionId,
+ const std::vector<uint8_t>& in_keyId,
+ const std::vector<uint8_t>& in_input,
+ const std::vector<uint8_t>& in_iv,
+ std::vector<uint8_t>* _aidl_return) override;
+ ::ndk::ScopedAStatus encrypt(const std::vector<uint8_t>& in_sessionId,
+ const std::vector<uint8_t>& in_keyId,
+ const std::vector<uint8_t>& in_input,
+ const std::vector<uint8_t>& in_iv,
+ std::vector<uint8_t>* _aidl_return) override;
+ ::ndk::ScopedAStatus getHdcpLevels(
+ ::aidl::android::hardware::drm::HdcpLevels* _aidl_return) override;
+ ::ndk::ScopedAStatus getKeyRequest(
+ const std::vector<uint8_t>& in_scope, const std::vector<uint8_t>& in_initData,
+ const std::string& in_mimeType, ::aidl::android::hardware::drm::KeyType in_keyType,
+ const std::vector<::aidl::android::hardware::drm::KeyValue>& in_optionalParameters,
+ ::aidl::android::hardware::drm::KeyRequest* _aidl_return) override;
+ ::ndk::ScopedAStatus getLogMessages(
+ std::vector<::aidl::android::hardware::drm::LogMessage>* _aidl_return) override;
+
+ ::ndk::ScopedAStatus getMetrics(
+ std::vector<::aidl::android::hardware::drm::DrmMetricGroup>* _aidl_return) override;
+ ::ndk::ScopedAStatus getNumberOfSessions(
+ ::aidl::android::hardware::drm::NumberOfSessions* _aidl_return) override;
+ ::ndk::ScopedAStatus getOfflineLicenseKeySetIds(
+ std::vector<::aidl::android::hardware::drm::KeySetId>* _aidl_return) override;
+ ::ndk::ScopedAStatus getOfflineLicenseState(
+ const ::aidl::android::hardware::drm::KeySetId& in_keySetId,
+ ::aidl::android::hardware::drm::OfflineLicenseState* _aidl_return) override;
+ ::ndk::ScopedAStatus getPropertyByteArray(const std::string& in_propertyName,
+ std::vector<uint8_t>* _aidl_return) override;
+ ::ndk::ScopedAStatus getPropertyString(const std::string& in_propertyName,
+ std::string* _aidl_return) override;
+ ::ndk::ScopedAStatus getProvisionRequest(
+ const std::string& in_certificateType, const std::string& in_certificateAuthority,
+ ::aidl::android::hardware::drm::ProvisionRequest* _aidl_return) override;
+ ::ndk::ScopedAStatus getSecureStop(
+ const ::aidl::android::hardware::drm::SecureStopId& in_secureStopId,
+ ::aidl::android::hardware::drm::SecureStop* _aidl_return) override;
+ ::ndk::ScopedAStatus getSecureStopIds(
+ std::vector<::aidl::android::hardware::drm::SecureStopId>* _aidl_return) override;
+ ::ndk::ScopedAStatus getSecureStops(
+ std::vector<::aidl::android::hardware::drm::SecureStop>* _aidl_return) override;
+ ::ndk::ScopedAStatus getSecurityLevel(
+ const std::vector<uint8_t>& in_sessionId,
+ ::aidl::android::hardware::drm::SecurityLevel* _aidl_return) override;
+ ::ndk::ScopedAStatus openSession(::aidl::android::hardware::drm::SecurityLevel in_securityLevel,
+ std::vector<uint8_t>* _aidl_return) override;
+ ::ndk::ScopedAStatus provideKeyResponse(
+ const std::vector<uint8_t>& in_scope, const std::vector<uint8_t>& in_response,
+ ::aidl::android::hardware::drm::KeySetId* _aidl_return) override;
+ ::ndk::ScopedAStatus provideProvisionResponse(
+ const std::vector<uint8_t>& in_response,
+ ::aidl::android::hardware::drm::ProvideProvisionResponseResult* _aidl_return) override;
+ ::ndk::ScopedAStatus queryKeyStatus(
+ const std::vector<uint8_t>& in_sessionId,
+ std::vector<::aidl::android::hardware::drm::KeyValue>* _aidl_return) override;
+ ::ndk::ScopedAStatus releaseAllSecureStops() override;
+ ::ndk::ScopedAStatus releaseSecureStop(
+ const ::aidl::android::hardware::drm::SecureStopId& in_secureStopId) override;
+ ::ndk::ScopedAStatus releaseSecureStops(
+ const ::aidl::android::hardware::drm::OpaqueData& in_ssRelease) override;
+ ::ndk::ScopedAStatus removeAllSecureStops() override;
+ ::ndk::ScopedAStatus removeKeys(const std::vector<uint8_t>& in_sessionId) override;
+ ::ndk::ScopedAStatus removeOfflineLicense(
+ const ::aidl::android::hardware::drm::KeySetId& in_keySetId) override;
+ ::ndk::ScopedAStatus removeSecureStop(
+ const ::aidl::android::hardware::drm::SecureStopId& in_secureStopId) override;
+ ::ndk::ScopedAStatus requiresSecureDecoder(
+ const std::string& in_mime, ::aidl::android::hardware::drm::SecurityLevel in_level,
+ bool* _aidl_return) override;
+ ::ndk::ScopedAStatus requiresSecureDecoderDefault(const std::string& in_mime,
+ bool* _aidl_return) override;
+ ::ndk::ScopedAStatus restoreKeys(
+ const std::vector<uint8_t>& in_sessionId,
+ const ::aidl::android::hardware::drm::KeySetId& in_keySetId) override;
+ ::ndk::ScopedAStatus setCipherAlgorithm(const std::vector<uint8_t>& in_sessionId,
+ const std::string& in_algorithm) override;
+ ::ndk::ScopedAStatus setListener(
+ // const ::android::sp<::aidl::android::hardware::drm::IDrmPluginListener>&
+ // in_listener)
+ const std::shared_ptr<IDrmPluginListener>& in_listener) override;
+ ::ndk::ScopedAStatus setMacAlgorithm(const std::vector<uint8_t>& in_sessionId,
+ const std::string& in_algorithm) override;
+ ::ndk::ScopedAStatus setPlaybackId(const std::vector<uint8_t>& in_sessionId,
+ const std::string& in_playbackId) override;
+ ::ndk::ScopedAStatus setPropertyByteArray(const std::string& in_propertyName,
+ const std::vector<uint8_t>& in_value) override;
+ ::ndk::ScopedAStatus setPropertyString(const std::string& in_propertyName,
+ const std::string& in_value) override;
+ ::ndk::ScopedAStatus sign(const std::vector<uint8_t>& in_sessionId,
+ const std::vector<uint8_t>& in_keyId,
+ const std::vector<uint8_t>& in_message,
+ std::vector<uint8_t>* _aidl_return) override;
+ ::ndk::ScopedAStatus signRSA(const std::vector<uint8_t>& in_sessionId,
+ const std::string& in_algorithm,
+ const std::vector<uint8_t>& in_message,
+ const std::vector<uint8_t>& in_wrappedkey,
+ std::vector<uint8_t>* _aidl_return) override;
+ ::ndk::ScopedAStatus verify(const std::vector<uint8_t>& in_sessionId,
+ const std::vector<uint8_t>& in_keyId,
+ const std::vector<uint8_t>& in_message,
+ const std::vector<uint8_t>& in_signature,
+ bool* _aidl_return) override;
+
+ private:
+ void initProperties();
+ void installSecureStop(const std::vector<uint8_t>& sessionId);
+ bool makeKeySetId(std::string* keySetId);
+ void setPlayPolicy();
+
+ void sendEvent(::aidl::android::hardware::drm::EventType in_eventType,
+ const std::vector<uint8_t>& in_sessionId,
+ const std::vector<uint8_t>& in_data);
+ void sendExpirationUpdate(const std::vector<uint8_t>& in_sessionId,
+ int64_t in_expiryTimeInMS);
+ void sendKeysChange(
+ const std::vector<uint8_t>& in_sessionId,
+ const std::vector<::aidl::android::hardware::drm::KeyStatus>& in_keyStatusList,
+ bool in_hasNewUsableKey);
+ void sendSessionLostState(const std::vector<uint8_t>& in_sessionId);
+
+ Status setSecurityLevel(const std::vector<uint8_t>& sessionId, SecurityLevel level);
+
+ Status getKeyRequestCommon(const std::vector<uint8_t>& scope,
+ const std::vector<uint8_t>& initData, const std::string& mimeType,
+ KeyType keyType, const std::vector<KeyValue>& optionalParameters,
+ std::vector<uint8_t>* request, KeyRequestType* getKeyRequestType,
+ std::string* defaultUrl);
+
+ struct ClearkeySecureStop {
+ std::vector<uint8_t> id;
+ std::vector<uint8_t> data;
+ };
+
+ std::map<std::vector<uint8_t>, ClearkeySecureStop> mSecureStops;
+ std::vector<KeyValue> mPlayPolicy;
+ std::map<std::string, std::string> mStringProperties;
+ std::map<std::string, std::vector<uint8_t>> mByteArrayProperties;
+ std::map<std::string, std::vector<uint8_t>> mReleaseKeysMap;
+ std::map<std::vector<uint8_t>, std::string> mPlaybackId;
+ std::map<std::vector<uint8_t>, SecurityLevel> mSecurityLevel;
+ ::std::shared_ptr<IDrmPluginListener> mListener;
+ SessionLibrary* mSessionLibrary;
+ int64_t mOpenSessionOkCount;
+ int64_t mCloseSessionOkCount;
+ int64_t mCloseSessionNotOpenedCount;
+ uint32_t mNextSecureStopId;
+ ::android::Mutex mPlayPolicyLock;
+
+ // set by property to mock error scenarios
+ Status mMockError;
+
+ void processMockError(const ::android::sp<Session>& session) {
+ session->setMockError(static_cast<CdmResponseType>(mMockError));
+ mMockError = Status::OK;
+ }
+
+ DeviceFiles mFileHandle;
+ ::android::Mutex mSecureStopLock;
+
+ CLEARKEY_DISALLOW_COPY_AND_ASSIGN_AND_NEW(DrmPlugin);
+};
+
+} // namespace clearkey
+} // namespace drm
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/drm/mediadrm/plugins/clearkey/common/AesCtrDecryptor.cpp b/drm/mediadrm/plugins/clearkey/common/AesCtrDecryptor.cpp
new file mode 100644
index 0000000..0b97820
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/AesCtrDecryptor.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "clearkey-AesDecryptor"
+
+#include <utils/Log.h>
+
+#include <openssl/aes.h>
+
+#include "AesCtrDecryptor.h"
+#include "ClearKeyTypes.h"
+
+namespace clearkeydrm {
+
+static const size_t kBlockBitCount = kBlockSize * 8;
+
+CdmResponseType AesCtrDecryptor::decrypt(const std::vector<uint8_t>& key, const Iv iv,
+ const uint8_t* source, uint8_t* destination,
+ const std::vector<int32_t>& clearDataLengths,
+ const std::vector<int32_t>& encryptedDataLengths,
+ size_t* bytesDecryptedOut) {
+
+ if (key.size() != kBlockSize || clearDataLengths.size() != encryptedDataLengths.size()) {
+ android_errorWriteLog(0x534e4554, "63982768");
+ return clearkeydrm::ERROR_DECRYPT;
+ }
+
+ uint32_t blockOffset = 0;
+ uint8_t previousEncryptedCounter[kBlockSize];
+ memset(previousEncryptedCounter, 0, kBlockSize);
+
+ size_t offset = 0;
+ AES_KEY opensslKey;
+ AES_set_encrypt_key(key.data(), kBlockBitCount, &opensslKey);
+ Iv opensslIv;
+ memcpy(opensslIv, iv, sizeof(opensslIv));
+
+ for (size_t i = 0; i < clearDataLengths.size(); ++i) {
+ int32_t numBytesOfClearData = clearDataLengths[i];
+ if (numBytesOfClearData > 0) {
+ memcpy(destination + offset, source + offset, numBytesOfClearData);
+ offset += numBytesOfClearData;
+ }
+
+ int32_t numBytesOfEncryptedData = encryptedDataLengths[i];
+ if (numBytesOfEncryptedData > 0) {
+ AES_ctr128_encrypt(source + offset, destination + offset,
+ numBytesOfEncryptedData, &opensslKey, opensslIv,
+ previousEncryptedCounter, &blockOffset);
+ offset += numBytesOfEncryptedData;
+ }
+ }
+
+ *bytesDecryptedOut = offset;
+ return clearkeydrm::OK;
+}
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/Android.bp b/drm/mediadrm/plugins/clearkey/common/Android.bp
index 7ed8b88..a6a5b28 100644
--- a/drm/mediadrm/plugins/clearkey/common/Android.bp
+++ b/drm/mediadrm/plugins/clearkey/common/Android.bp
@@ -44,3 +44,56 @@
integer_overflow: true,
},
}
+
+cc_library_static {
+ name: "libclearkeydevicefiles-protos.common",
+ vendor: true,
+
+ proto: {
+ export_proto_headers: true,
+ type: "lite",
+ },
+ srcs: ["protos/DeviceFiles.proto"],
+}
+
+cc_library_static {
+ name: "libclearkeybase",
+ vendor: true,
+
+ srcs: [
+ "AesCtrDecryptor.cpp",
+ "Base64.cpp",
+ "Buffer.cpp",
+ "ClearKeyUUID.cpp",
+ "DeviceFiles.cpp",
+ "InitDataParser.cpp",
+ "JsonWebKey.cpp",
+ "MemoryFileSystem.cpp",
+ "Session.cpp",
+ "SessionLibrary.cpp",
+ "Utils.cpp",
+ ],
+
+ cflags: ["-Wall", "-Werror"],
+
+ include_dirs: ["frameworks/av/include"],
+
+ shared_libs: [
+ "libutils",
+ "libcrypto",
+ ],
+
+ whole_static_libs: [
+ "libjsmn",
+ "libclearkeydevicefiles-protos.common",
+ ],
+
+ export_include_dirs: [
+ "include",
+ "include/clearkeydrm",
+ ],
+
+ sanitize: {
+ integer_overflow: true,
+ },
+}
diff --git a/drm/mediadrm/plugins/clearkey/common/Base64.cpp b/drm/mediadrm/plugins/clearkey/common/Base64.cpp
new file mode 100644
index 0000000..6499793
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/Base64.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "clearkey-Base64"
+
+#include "Base64.h"
+
+#include <string>
+
+namespace clearkeydrm {
+
+::android::sp<Buffer> decodeBase64(const std::string& s) {
+ size_t n = s.size();
+
+ if ((n % 4) != 0) {
+ return nullptr;
+ }
+
+ size_t padding = 0;
+ if (n >= 1 && s.c_str()[n - 1] == '=') {
+ padding = 1;
+
+ if (n >= 2 && s.c_str()[n - 2] == '=') {
+ padding = 2;
+
+ if (n >= 3 && s.c_str()[n - 3] == '=') {
+ padding = 3;
+ }
+ }
+ }
+
+ // We divide first to avoid overflow. It's OK to do this because we
+ // already made sure that n % 4 == 0.
+ size_t outLen = (n / 4) * 3 - padding;
+
+ ::android::sp<Buffer> buffer = new Buffer(outLen);
+ uint8_t* out = buffer->data();
+ if (out == nullptr || buffer->size() < outLen) {
+ return nullptr;
+ }
+
+ size_t j = 0;
+ uint32_t accum = 0;
+ for (size_t i = 0; i < n; ++i) {
+ char c = s.c_str()[i];
+ unsigned value;
+ if (c >= 'A' && c <= 'Z') {
+ value = c - 'A';
+ } else if (c >= 'a' && c <= 'z') {
+ value = 26 + c - 'a';
+ } else if (c >= '0' && c <= '9') {
+ value = 52 + c - '0';
+ } else if (c == '+' || c == '-') {
+ value = 62;
+ } else if (c == '/' || c == '_') {
+ value = 63;
+ } else if (c != '=') {
+ return nullptr;
+ } else {
+ if (i < n - padding) {
+ return nullptr;
+ }
+
+ value = 0;
+ }
+
+ accum = (accum << 6) | value;
+
+ if (((i + 1) % 4) == 0) {
+ if (j < outLen) {
+ out[j++] = (accum >> 16);
+ }
+ if (j < outLen) {
+ out[j++] = (accum >> 8) & 0xff;
+ }
+ if (j < outLen) {
+ out[j++] = accum & 0xff;
+ }
+
+ accum = 0;
+ }
+ }
+
+ return buffer;
+}
+
+static char encode6Bit(unsigned x) {
+ if (x <= 25) {
+ return 'A' + x;
+ } else if (x <= 51) {
+ return 'a' + x - 26;
+ } else if (x <= 61) {
+ return '0' + x - 52;
+ } else if (x == 62) {
+ return '+';
+ } else {
+ return '/';
+ }
+}
+
+void encodeBase64(const void* _data, size_t size, std::string* out) {
+ out->clear();
+
+ const uint8_t* data = (const uint8_t*)_data;
+
+ size_t i;
+ for (i = 0; i < (size / 3) * 3; i += 3) {
+ uint8_t x1 = data[i];
+ uint8_t x2 = data[i + 1];
+ uint8_t x3 = data[i + 2];
+
+ out->push_back(encode6Bit(x1 >> 2));
+ out->push_back(encode6Bit((x1 << 4 | x2 >> 4) & 0x3f));
+ out->push_back(encode6Bit((x2 << 2 | x3 >> 6) & 0x3f));
+ out->push_back(encode6Bit(x3 & 0x3f));
+ }
+ switch (size % 3) {
+ case 0:
+ break;
+ case 2: {
+ uint8_t x1 = data[i];
+ uint8_t x2 = data[i + 1];
+ out->push_back(encode6Bit(x1 >> 2));
+ out->push_back(encode6Bit((x1 << 4 | x2 >> 4) & 0x3f));
+ out->push_back(encode6Bit((x2 << 2) & 0x3f));
+ out->push_back('=');
+ break;
+ }
+ default: {
+ uint8_t x1 = data[i];
+ out->push_back(encode6Bit(x1 >> 2));
+ out->push_back(encode6Bit((x1 << 4) & 0x3f));
+ out->append("==");
+ break;
+ }
+ }
+}
+
+void encodeBase64Url(const void* _data, size_t size, std::string* out) {
+ encodeBase64(_data, size, out);
+
+ if ((std::string::npos != out->find("+")) || (std::string::npos != out->find("/"))) {
+ size_t outLen = out->size();
+ char* base64url = new char[outLen];
+ for (size_t i = 0; i < outLen; ++i) {
+ if (out->c_str()[i] == '+')
+ base64url[i] = '-';
+ else if (out->c_str()[i] == '/')
+ base64url[i] = '_';
+ else
+ base64url[i] = out->c_str()[i];
+ }
+
+ out->assign(base64url, outLen);
+ delete[] base64url;
+ }
+}
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/Buffer.cpp b/drm/mediadrm/plugins/clearkey/common/Buffer.cpp
new file mode 100644
index 0000000..1671598
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/Buffer.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "Buffer.h"
+
+namespace clearkeydrm {
+
+Buffer::Buffer(size_t capacity) : mRangeOffset(0), mOwnsData(true) {
+ mData = malloc(capacity);
+ if (mData == nullptr) {
+ mCapacity = 0;
+ mRangeLength = 0;
+ } else {
+ mCapacity = capacity;
+ mRangeLength = capacity;
+ }
+}
+
+Buffer::~Buffer() {
+ if (mOwnsData) {
+ if (mData != nullptr) {
+ free(mData);
+ mData = nullptr;
+ }
+ }
+}
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/DeviceFiles.cpp b/drm/mediadrm/plugins/clearkey/common/DeviceFiles.cpp
new file mode 100644
index 0000000..2299249
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/DeviceFiles.cpp
@@ -0,0 +1,251 @@
+/*
+ * 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.
+ */
+#include <utils/Log.h>
+
+#include <sys/stat.h>
+#include <string>
+
+#include "DeviceFiles.h"
+#include "protos/DeviceFiles.pb.h"
+
+#include <openssl/sha.h>
+
+// Protobuf generated classes.
+using clearkeydrm::HashedFile;
+using clearkeydrm::License;
+using clearkeydrm::License_LicenseState_ACTIVE;
+using clearkeydrm::License_LicenseState_RELEASING;
+using clearkeydrm::OfflineFile;
+
+namespace {
+const char kLicenseFileNameExt[] = ".lic";
+
+bool Hash(const std::string& data, std::string* hash) {
+ if (!hash) return false;
+
+ hash->resize(SHA256_DIGEST_LENGTH);
+
+ const unsigned char* input = reinterpret_cast<const unsigned char*>(data.data());
+ unsigned char* output = reinterpret_cast<unsigned char*>(&(*hash)[0]);
+ SHA256(input, data.size(), output);
+ return true;
+}
+
+} // namespace
+
+namespace clearkeydrm {
+
+bool DeviceFiles::StoreLicense(const std::string& keySetId, LicenseState state,
+ const std::string& licenseResponse) {
+ OfflineFile file;
+ file.set_type(OfflineFile::LICENSE);
+ file.set_version(OfflineFile::VERSION_1);
+
+ License* license = file.mutable_license();
+ switch (state) {
+ case kLicenseStateActive:
+ license->set_state(License_LicenseState_ACTIVE);
+ license->set_license(licenseResponse);
+ break;
+ case kLicenseStateReleasing:
+ license->set_state(License_LicenseState_RELEASING);
+ license->set_license(licenseResponse);
+ break;
+ default:
+ ALOGW("StoreLicense: Unknown license state: %u", state);
+ return false;
+ }
+
+ std::string serializedFile;
+ file.SerializeToString(&serializedFile);
+
+ return StoreFileWithHash(keySetId + kLicenseFileNameExt, serializedFile);
+}
+
+bool DeviceFiles::StoreFileWithHash(const std::string& fileName,
+ const std::string& serializedFile) {
+ std::string hash;
+ if (!Hash(serializedFile, &hash)) {
+ ALOGE("StoreFileWithHash: Failed to compute hash");
+ return false;
+ }
+
+ HashedFile hashFile;
+ hashFile.set_file(serializedFile);
+ hashFile.set_hash(hash);
+
+ std::string serializedHashFile;
+ hashFile.SerializeToString(&serializedHashFile);
+
+ return StoreFileRaw(fileName, serializedHashFile);
+}
+
+bool DeviceFiles::StoreFileRaw(const std::string& fileName, const std::string& serializedHashFile) {
+ MemoryFileSystem::MemoryFile memFile;
+ memFile.setFileName(fileName);
+ memFile.setContent(serializedHashFile);
+ memFile.setFileSize(serializedHashFile.size());
+ size_t len = mFileHandle.Write(fileName, memFile);
+
+ if (len != static_cast<size_t>(serializedHashFile.size())) {
+ ALOGE("StoreFileRaw: Failed to write %s", fileName.c_str());
+ ALOGD("StoreFileRaw: expected=%zd, actual=%zu", serializedHashFile.size(), len);
+ return false;
+ }
+
+ ALOGD("StoreFileRaw: wrote %zu bytes to %s", serializedHashFile.size(), fileName.c_str());
+ return true;
+}
+
+bool DeviceFiles::RetrieveLicense(const std::string& keySetId, LicenseState* state,
+ std::string* offlineLicense) {
+ OfflineFile file;
+ if (!RetrieveHashedFile(keySetId + kLicenseFileNameExt, &file)) {
+ return false;
+ }
+
+ if (file.type() != OfflineFile::LICENSE) {
+ ALOGE("RetrieveLicense: Invalid file type");
+ return false;
+ }
+
+ if (file.version() != OfflineFile::VERSION_1) {
+ ALOGE("RetrieveLicense: Invalid file version");
+ return false;
+ }
+
+ if (!file.has_license()) {
+ ALOGE("RetrieveLicense: License not present");
+ return false;
+ }
+
+ License license = file.license();
+ switch (license.state()) {
+ case License_LicenseState_ACTIVE:
+ *state = kLicenseStateActive;
+ break;
+ case License_LicenseState_RELEASING:
+ *state = kLicenseStateReleasing;
+ break;
+ default:
+ ALOGW("RetrieveLicense: Unrecognized license state: %u", kLicenseStateUnknown);
+ *state = kLicenseStateUnknown;
+ break;
+ }
+ *offlineLicense = license.license();
+ return true;
+}
+
+bool DeviceFiles::DeleteLicense(const std::string& keySetId) {
+ return mFileHandle.RemoveFile(keySetId + kLicenseFileNameExt);
+}
+
+bool DeviceFiles::DeleteAllLicenses() {
+ return mFileHandle.RemoveAllFiles();
+}
+
+bool DeviceFiles::LicenseExists(const std::string& keySetId) {
+ return mFileHandle.FileExists(keySetId + kLicenseFileNameExt);
+}
+
+std::vector<std::string> DeviceFiles::ListLicenses() const {
+ std::vector<std::string> licenses = mFileHandle.ListFiles();
+ for (size_t i = 0; i < licenses.size(); i++) {
+ std::string& license = licenses[i];
+ license = license.substr(0, license.size() - strlen(kLicenseFileNameExt));
+ }
+ return licenses;
+}
+
+bool DeviceFiles::RetrieveHashedFile(const std::string& fileName, OfflineFile* deSerializedFile) {
+ if (!deSerializedFile) {
+ ALOGE("RetrieveHashedFile: invalid file parameter");
+ return false;
+ }
+
+ if (!FileExists(fileName)) {
+ ALOGE("RetrieveHashedFile: %s does not exist", fileName.c_str());
+ return false;
+ }
+
+ ssize_t bytes = GetFileSize(fileName);
+ if (bytes <= 0) {
+ ALOGE("RetrieveHashedFile: invalid file size: %s", fileName.c_str());
+ // Remove the corrupted file so the caller will not get the same error
+ // when trying to access the file repeatedly, causing the system to stall.
+ RemoveFile(fileName);
+ return false;
+ }
+
+ std::string serializedHashFile;
+ serializedHashFile.resize(bytes);
+ bytes = mFileHandle.Read(fileName, &serializedHashFile);
+
+ if (bytes != static_cast<ssize_t>(serializedHashFile.size())) {
+ ALOGE("RetrieveHashedFile: Failed to read from %s", fileName.c_str());
+ ALOGV("RetrieveHashedFile: expected: %zd, actual: %zd", serializedHashFile.size(), bytes);
+ // Remove the corrupted file so the caller will not get the same error
+ // when trying to access the file repeatedly, causing the system to stall.
+ RemoveFile(fileName);
+ return false;
+ }
+
+ ALOGV("RetrieveHashedFile: read %zd from %s", bytes, fileName.c_str());
+
+ HashedFile hashFile;
+ if (!hashFile.ParseFromString(serializedHashFile)) {
+ ALOGE("RetrieveHashedFile: Unable to parse hash file");
+ // Remove corrupt file.
+ RemoveFile(fileName);
+ return false;
+ }
+
+ std::string hash;
+ if (!Hash(hashFile.file(), &hash)) {
+ ALOGE("RetrieveHashedFile: Hash computation failed");
+ return false;
+ }
+
+ if (hash != hashFile.hash()) {
+ ALOGE("RetrieveHashedFile: Hash mismatch");
+ // Remove corrupt file.
+ RemoveFile(fileName);
+ return false;
+ }
+
+ if (!deSerializedFile->ParseFromString(hashFile.file())) {
+ ALOGE("RetrieveHashedFile: Unable to parse file");
+ // Remove corrupt file.
+ RemoveFile(fileName);
+ return false;
+ }
+
+ return true;
+}
+
+bool DeviceFiles::FileExists(const std::string& fileName) const {
+ return mFileHandle.FileExists(fileName);
+}
+
+bool DeviceFiles::RemoveFile(const std::string& fileName) {
+ return mFileHandle.RemoveFile(fileName);
+}
+
+ssize_t DeviceFiles::GetFileSize(const std::string& fileName) const {
+ return mFileHandle.GetFileSize(fileName);
+}
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/InitDataParser.cpp b/drm/mediadrm/plugins/clearkey/common/InitDataParser.cpp
new file mode 100644
index 0000000..fc839e9
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/InitDataParser.cpp
@@ -0,0 +1,172 @@
+/*
+ * 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 "clearkey-InitDataParser"
+
+#include <algorithm>
+#include <arpa/inet.h>
+#include <utils/Log.h>
+
+#include "InitDataParser.h"
+
+#include "Base64.h"
+
+#include "ClearKeyUUID.h"
+#include "MimeType.h"
+
+namespace {
+const size_t kKeyIdSize = 16;
+const size_t kSystemIdSize = 16;
+} // namespace
+
+namespace clearkeydrm {
+
+std::vector<uint8_t> StrToVector(const std::string& str) {
+ std::vector<uint8_t> vec(str.begin(), str.end());
+ return vec;
+}
+
+CdmResponseType InitDataParser::parse(const std::vector<uint8_t>& initData,
+ const std::string& mimeType,
+ CdmKeyType keyType,
+ std::vector<uint8_t>* licenseRequest) {
+ // Build a list of the key IDs
+ std::vector<const uint8_t*> keyIds;
+
+ if (mimeType == kIsoBmffVideoMimeType.c_str() || mimeType == kIsoBmffAudioMimeType.c_str() ||
+ mimeType == kCencInitDataFormat.c_str()) {
+ auto res = parsePssh(initData, &keyIds);
+ if (res != clearkeydrm::OK) {
+ return res;
+ }
+ } else if (mimeType == kWebmVideoMimeType.c_str() || mimeType == kWebmAudioMimeType.c_str() ||
+ mimeType == kWebmInitDataFormat.c_str()) {
+ // WebM "init data" is just a single key ID
+ if (initData.size() != kKeyIdSize) {
+ return clearkeydrm::ERROR_CANNOT_HANDLE;
+ }
+ keyIds.push_back(initData.data());
+ } else {
+ return clearkeydrm::ERROR_CANNOT_HANDLE;
+ }
+
+ if (keyType == clearkeydrm::KEY_TYPE_RELEASE) {
+ // restore key
+ }
+
+ // Build the request
+ std::string requestJson = generateRequest(keyType, keyIds);
+ std::vector<uint8_t> requestJsonVec = StrToVector(requestJson);
+
+ licenseRequest->clear();
+ licenseRequest->insert(licenseRequest->end(), requestJsonVec.begin(), requestJsonVec.end());
+ return clearkeydrm::OK;
+}
+
+CdmResponseType InitDataParser::parsePssh(const std::vector<uint8_t>& initData,
+ std::vector<const uint8_t*>* keyIds) {
+ // Description of PSSH format:
+ // https://w3c.github.io/encrypted-media/format-registry/initdata/cenc.html
+ size_t readPosition = 0;
+
+ uint32_t expectedSize = initData.size();
+ const char psshIdentifier[4] = {'p', 's', 's', 'h'};
+ const uint8_t psshVersion1[4] = {1, 0, 0, 0};
+ uint32_t keyIdCount = 0;
+ size_t headerSize = sizeof(expectedSize) + sizeof(psshIdentifier) + sizeof(psshVersion1) +
+ kSystemIdSize + sizeof(keyIdCount);
+ if (initData.size() < headerSize) {
+ return clearkeydrm::ERROR_CANNOT_HANDLE;
+ }
+
+ // Validate size field
+ expectedSize = htonl(expectedSize);
+ if (memcmp(&initData[readPosition], &expectedSize, sizeof(expectedSize)) != 0) {
+ return clearkeydrm::ERROR_CANNOT_HANDLE;
+ }
+ readPosition += sizeof(expectedSize);
+
+ // Validate PSSH box identifier
+ if (memcmp(&initData[readPosition], psshIdentifier, sizeof(psshIdentifier)) != 0) {
+ return clearkeydrm::ERROR_CANNOT_HANDLE;
+ }
+ readPosition += sizeof(psshIdentifier);
+
+ // Validate EME version number
+ if (memcmp(&initData[readPosition], psshVersion1, sizeof(psshVersion1)) != 0) {
+ return clearkeydrm::ERROR_CANNOT_HANDLE;
+ }
+ readPosition += sizeof(psshVersion1);
+
+ // Validate system ID
+ if (!isClearKeyUUID(&initData[readPosition])) {
+ return clearkeydrm::ERROR_CANNOT_HANDLE;
+ }
+ readPosition += kSystemIdSize;
+
+ // Read key ID count
+ memcpy(&keyIdCount, &initData[readPosition], sizeof(keyIdCount));
+ keyIdCount = ntohl(keyIdCount);
+ readPosition += sizeof(keyIdCount);
+
+ uint64_t psshSize = 0;
+ if (__builtin_mul_overflow(keyIdCount, kKeyIdSize, &psshSize) ||
+ __builtin_add_overflow(readPosition, psshSize, &psshSize) ||
+ psshSize != initData.size() - sizeof(uint32_t) /* DataSize(0) */) {
+ return clearkeydrm::ERROR_CANNOT_HANDLE;
+ }
+
+ // Calculate the key ID offsets
+ for (uint32_t i = 0; i < keyIdCount; ++i) {
+ size_t keyIdPosition = readPosition + (i * kKeyIdSize);
+ keyIds->push_back(&initData[keyIdPosition]);
+ }
+ return clearkeydrm::OK;
+}
+
+std::string InitDataParser::generateRequest(CdmKeyType keyType,
+ const std::vector<const uint8_t*>& keyIds) {
+ const std::string kRequestPrefix("{\"kids\":[");
+ const std::string kTemporarySession("],\"type\":\"temporary\"}");
+ const std::string kPersistentSession("],\"type\":\"persistent-license\"}");
+
+ std::string request(kRequestPrefix);
+ std::string encodedId;
+ for (size_t i = 0; i < keyIds.size(); ++i) {
+ encodedId.clear();
+ encodeBase64Url(keyIds[i], kKeyIdSize, &encodedId);
+ if (i != 0) {
+ request.append(",");
+ }
+ request.push_back('\"');
+ request.append(encodedId);
+ request.push_back('\"');
+ }
+ if (keyType == clearkeydrm::KEY_TYPE_STREAMING) {
+ request.append(kTemporarySession);
+ } else if (keyType == clearkeydrm::KEY_TYPE_OFFLINE ||
+ keyType == clearkeydrm::KEY_TYPE_RELEASE) {
+ request.append(kPersistentSession);
+ }
+
+ // Android's Base64 encoder produces padding. EME forbids padding.
+ const char kBase64Padding = '=';
+ request.erase(std::remove(request.begin(), request.end(), kBase64Padding), request.end());
+
+ return request;
+}
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/JsonWebKey.cpp b/drm/mediadrm/plugins/clearkey/common/JsonWebKey.cpp
new file mode 100644
index 0000000..ddbc594
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/JsonWebKey.cpp
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "clearkey-JsonWebKey"
+
+#include <utils/Log.h>
+
+#include "JsonWebKey.h"
+
+#include "Base64.h"
+
+namespace {
+const std::string kBase64Padding("=");
+const std::string kKeysTag("keys");
+const std::string kKeyTypeTag("kty");
+const std::string kKeyTag("k");
+const std::string kKeyIdTag("kid");
+const std::string kMediaSessionType("type");
+const std::string kPersistentLicenseSession("persistent-license");
+const std::string kSymmetricKeyValue("oct");
+const std::string kTemporaryLicenseSession("temporary");
+} // namespace
+
+namespace clearkeydrm {
+
+JsonWebKey::JsonWebKey() {}
+
+JsonWebKey::~JsonWebKey() {}
+
+/*
+ * Parses a JSON Web Key Set string, initializes a KeyMap with key id:key
+ * pairs from the JSON Web Key Set. Both key ids and keys are base64url
+ * encoded. The KeyMap contains base64url decoded key id:key pairs.
+ *
+ * @return Returns false for errors, true for success.
+ */
+bool JsonWebKey::extractKeysFromJsonWebKeySet(const std::string& jsonWebKeySet, KeyMap* keys) {
+ keys->clear();
+
+ if (!parseJsonWebKeySet(jsonWebKeySet, &mJsonObjects)) {
+ return false;
+ }
+
+ // mJsonObjects[0] contains the entire JSON Web Key Set, including
+ // 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 (mJsonObjects.size() == 0 || !isJsonWebKeySet(mJsonObjects[0])) {
+ return false;
+ }
+
+ std::string encodedKey, encodedKeyId;
+ std::vector<uint8_t> decodedKey, decodedKeyId;
+
+ // mJsonObjects[1] contains the first JSON Web Key in the set
+ for (size_t i = 1; i < mJsonObjects.size(); ++i) {
+ encodedKeyId.clear();
+ encodedKey.clear();
+
+ if (!parseJsonObject(mJsonObjects[i], &mTokens)) return false;
+
+ if (findKey(mJsonObjects[i], &encodedKeyId, &encodedKey)) {
+ if (encodedKeyId.empty() || encodedKey.empty()) {
+ ALOGE("Must have both key id and key in the JsonWebKey set.");
+ continue;
+ }
+
+ if (!decodeBase64String(encodedKeyId, &decodedKeyId)) {
+ ALOGE("Failed to decode key id(%s)", encodedKeyId.c_str());
+ continue;
+ }
+
+ if (!decodeBase64String(encodedKey, &decodedKey)) {
+ ALOGE("Failed to decode key(%s)", encodedKey.c_str());
+ continue;
+ }
+
+ keys->insert(std::pair<std::vector<uint8_t>, std::vector<uint8_t>>(decodedKeyId,
+ decodedKey));
+ }
+ }
+ return true;
+}
+
+bool JsonWebKey::decodeBase64String(const std::string& encodedText,
+ std::vector<uint8_t>* decodedText) {
+ decodedText->clear();
+
+ // encodedText should not contain padding characters as per EME spec.
+ if (encodedText.find(kBase64Padding) != std::string::npos) {
+ return false;
+ }
+
+ // Since decodeBase64() requires padding characters,
+ // add them so length of encodedText is exactly a multiple of 4.
+ int remainder = encodedText.length() % 4;
+ std::string paddedText(encodedText);
+ if (remainder > 0) {
+ for (int i = 0; i < 4 - remainder; ++i) {
+ paddedText.append(kBase64Padding);
+ }
+ }
+
+ ::android::sp<Buffer> buffer = decodeBase64(paddedText);
+ if (buffer == nullptr) {
+ ALOGE("Malformed base64 encoded content found.");
+ return false;
+ }
+
+ decodedText->insert(decodedText->end(), buffer->base(), buffer->base() + buffer->size());
+ return true;
+}
+
+bool JsonWebKey::findKey(const std::string& jsonObject, std::string* keyId,
+ std::string* encodedKey) {
+ std::string key, value;
+
+ // Only allow symmetric key, i.e. "kty":"oct" pair.
+ if (jsonObject.find(kKeyTypeTag) != std::string::npos) {
+ findValue(kKeyTypeTag, &value);
+ if (0 != value.compare(kSymmetricKeyValue)) return false;
+ }
+
+ if (jsonObject.find(kKeyIdTag) != std::string::npos) {
+ findValue(kKeyIdTag, keyId);
+ }
+
+ if (jsonObject.find(kKeyTag) != std::string::npos) {
+ findValue(kKeyTag, encodedKey);
+ }
+ return true;
+}
+
+void JsonWebKey::findValue(const std::string& key, std::string* value) {
+ value->clear();
+ const char* valueToken;
+ for (std::vector<std::string>::const_iterator nextToken = mTokens.begin();
+ nextToken != mTokens.end(); ++nextToken) {
+ if (0 == (*nextToken).compare(key)) {
+ if (nextToken + 1 == mTokens.end()) break;
+ valueToken = (*(nextToken + 1)).c_str();
+ value->assign(valueToken);
+ nextToken++;
+ break;
+ }
+ }
+}
+
+bool JsonWebKey::isJsonWebKeySet(const std::string& jsonObject) const {
+ if (jsonObject.find(kKeysTag) == std::string::npos) {
+ ALOGE("JSON Web Key does not contain keys.");
+ return false;
+ }
+ return true;
+}
+
+/*
+ * Parses a JSON objects string and initializes a vector of tokens.
+ *
+ * @return Returns false for errors, true for success.
+ */
+bool JsonWebKey::parseJsonObject(const std::string& jsonObject, std::vector<std::string>* tokens) {
+ jsmn_parser parser;
+
+ jsmn_init(&parser);
+ int numTokens = jsmn_parse(&parser, jsonObject.c_str(), jsonObject.size(), nullptr, 0);
+ if (numTokens < 0) {
+ ALOGE("Parser returns error code=%d", numTokens);
+ return false;
+ }
+
+ unsigned int jsmnTokensSize = numTokens * sizeof(jsmntok_t);
+ mJsmnTokens.clear();
+ mJsmnTokens.resize(jsmnTokensSize);
+
+ jsmn_init(&parser);
+ int status = jsmn_parse(&parser, jsonObject.c_str(), jsonObject.size(), mJsmnTokens.data(),
+ numTokens);
+ if (status < 0) {
+ ALOGE("Parser returns error code=%d", status);
+ return false;
+ }
+
+ tokens->clear();
+ std::string token;
+ const char* pjs;
+ for (int j = 0; j < numTokens; ++j) {
+ pjs = jsonObject.c_str() + mJsmnTokens[j].start;
+ if (mJsmnTokens[j].type == JSMN_STRING || mJsmnTokens[j].type == JSMN_PRIMITIVE) {
+ token.assign(pjs, mJsmnTokens[j].end - mJsmnTokens[j].start);
+ tokens->push_back(token);
+ }
+ }
+ return true;
+}
+
+/*
+ * Parses JSON Web Key Set string and initializes a vector of JSON objects.
+ *
+ * @return Returns false for errors, true for success.
+ */
+bool JsonWebKey::parseJsonWebKeySet(const std::string& jsonWebKeySet,
+ std::vector<std::string>* jsonObjects) {
+ if (jsonWebKeySet.empty()) {
+ ALOGE("Empty JSON Web Key");
+ return false;
+ }
+
+ // The jsmn parser only supports unicode encoding.
+ jsmn_parser parser;
+
+ // Computes number of tokens. A token marks the type, offset in
+ // the original string.
+ jsmn_init(&parser);
+ int numTokens = jsmn_parse(&parser, jsonWebKeySet.c_str(), jsonWebKeySet.size(), nullptr, 0);
+ if (numTokens < 0) {
+ ALOGE("Parser returns error code=%d", numTokens);
+ return false;
+ }
+
+ unsigned int jsmnTokensSize = numTokens * sizeof(jsmntok_t);
+ mJsmnTokens.resize(jsmnTokensSize);
+
+ jsmn_init(&parser);
+ int status = jsmn_parse(&parser, jsonWebKeySet.c_str(), jsonWebKeySet.size(),
+ mJsmnTokens.data(), numTokens);
+ if (status < 0) {
+ ALOGE("Parser returns error code=%d", status);
+ return false;
+ }
+
+ std::string token;
+ const char* pjs;
+ for (int i = 0; i < numTokens; ++i) {
+ pjs = jsonWebKeySet.c_str() + mJsmnTokens[i].start;
+ if (mJsmnTokens[i].type == JSMN_OBJECT) {
+ token.assign(pjs, mJsmnTokens[i].end - mJsmnTokens[i].start);
+ jsonObjects->push_back(token);
+ }
+ }
+ return true;
+}
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/MemoryFileSystem.cpp b/drm/mediadrm/plugins/clearkey/common/MemoryFileSystem.cpp
new file mode 100644
index 0000000..1045458
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/MemoryFileSystem.cpp
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+#include <utils/Log.h>
+#include <string>
+#include <vector>
+
+#include "MemoryFileSystem.h"
+
+namespace clearkeydrm {
+
+std::string MemoryFileSystem::GetFileName(const std::string& path) {
+ size_t index = path.find_last_of('/');
+ if (index != std::string::npos) {
+ return path.substr(index + 1);
+ } else {
+ return path;
+ }
+}
+
+bool MemoryFileSystem::FileExists(const std::string& fileName) const {
+ auto result = mMemoryFileSystem.find(fileName);
+ return result != mMemoryFileSystem.end();
+}
+
+ssize_t MemoryFileSystem::GetFileSize(const std::string& fileName) const {
+ auto result = mMemoryFileSystem.find(fileName);
+ if (result != mMemoryFileSystem.end()) {
+ return static_cast<ssize_t>(result->second.getFileSize());
+ } else {
+ ALOGE("Failed to get size for %s", fileName.c_str());
+ return -1;
+ }
+}
+
+std::vector<std::string> MemoryFileSystem::ListFiles() const {
+ std::vector<std::string> list;
+ for (const auto& filename : mMemoryFileSystem) {
+ list.push_back(filename.first);
+ }
+ return list;
+}
+
+size_t MemoryFileSystem::Read(const std::string& path, std::string* buffer) {
+ std::string key = GetFileName(path);
+ auto result = mMemoryFileSystem.find(key);
+ if (result != mMemoryFileSystem.end()) {
+ std::string serializedHashFile = result->second.getContent();
+ buffer->assign(serializedHashFile);
+ return buffer->size();
+ } else {
+ ALOGE("Failed to read from %s", path.c_str());
+ return -1;
+ }
+}
+
+size_t MemoryFileSystem::Write(const std::string& path, const MemoryFile& memoryFile) {
+ std::string key = GetFileName(path);
+ auto result = mMemoryFileSystem.find(key);
+ if (result != mMemoryFileSystem.end()) {
+ mMemoryFileSystem.erase(key);
+ }
+ mMemoryFileSystem.insert(std::pair<std::string, MemoryFile>(key, memoryFile));
+ return memoryFile.getFileSize();
+}
+
+bool MemoryFileSystem::RemoveFile(const std::string& fileName) {
+ auto result = mMemoryFileSystem.find(fileName);
+ if (result != mMemoryFileSystem.end()) {
+ mMemoryFileSystem.erase(result);
+ return true;
+ } else {
+ ALOGE("Cannot find license to remove: %s", fileName.c_str());
+ return false;
+ }
+}
+
+bool MemoryFileSystem::RemoveAllFiles() {
+ mMemoryFileSystem.clear();
+ return mMemoryFileSystem.empty();
+}
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/Session.cpp b/drm/mediadrm/plugins/clearkey/common/Session.cpp
new file mode 100644
index 0000000..d7fd13a
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/Session.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "clearkey-Session"
+
+#include <utils/Log.h>
+
+#include "Session.h"
+
+#include "AesCtrDecryptor.h"
+#include "InitDataParser.h"
+#include "JsonWebKey.h"
+
+namespace clearkeydrm {
+
+using ::android::Mutex;
+using ::android::sp;
+
+CdmResponseType Session::getKeyRequest(const std::vector<uint8_t>& initData,
+ const std::string& mimeType,
+ CdmKeyType keyType,
+ std::vector<uint8_t>* keyRequest) const {
+ InitDataParser parser;
+ return parser.parse(initData, mimeType, keyType, keyRequest);
+}
+
+CdmResponseType Session::provideKeyResponse(const std::vector<uint8_t>& response) {
+ std::string responseString(reinterpret_cast<const char*>(response.data()), response.size());
+ KeyMap keys;
+
+ Mutex::Autolock lock(mMapLock);
+ JsonWebKey parser;
+ if (parser.extractKeysFromJsonWebKeySet(responseString, &keys)) {
+ for (auto& key : keys) {
+ std::string first(key.first.begin(), key.first.end());
+ std::string second(key.second.begin(), key.second.end());
+ mKeyMap.insert(
+ std::pair<std::vector<uint8_t>, std::vector<uint8_t>>(key.first, key.second));
+ }
+ return clearkeydrm::OK;
+ } else {
+ return clearkeydrm::ERROR_UNKNOWN;
+ }
+}
+
+CdmResponseType Session::decrypt(const KeyId keyId, const Iv iv,
+ const uint8_t* srcPtr, uint8_t* destPtr,
+ const std::vector<int32_t>& clearDataLengths,
+ const std::vector<int32_t>& encryptedDataLengths,
+ size_t* bytesDecryptedOut) {
+ Mutex::Autolock lock(mMapLock);
+
+ if (getMockError() != clearkeydrm::OK) {
+ return getMockError();
+ }
+
+ std::vector<uint8_t> keyIdVector;
+ keyIdVector.clear();
+ keyIdVector.insert(keyIdVector.end(), keyId, keyId + kBlockSize);
+ std::map<std::vector<uint8_t>, std::vector<uint8_t>>::iterator itr;
+ itr = mKeyMap.find(keyIdVector);
+ if (itr == mKeyMap.end()) {
+ return clearkeydrm::ERROR_NO_LICENSE;
+ }
+
+ clearkeydrm::AesCtrDecryptor decryptor;
+ auto status = decryptor.decrypt(itr->second /*key*/, iv, srcPtr, destPtr,
+ clearDataLengths,
+ encryptedDataLengths,
+ bytesDecryptedOut);
+ return status;
+}
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/SessionLibrary.cpp b/drm/mediadrm/plugins/clearkey/common/SessionLibrary.cpp
new file mode 100644
index 0000000..6b2ff38
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/SessionLibrary.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "clearkey-SessionLibrary"
+
+#include <utils/Log.h>
+
+#include "SessionLibrary.h"
+
+namespace clearkeydrm {
+
+using ::android::Mutex;
+using ::android::sp;
+
+Mutex SessionLibrary::sSingletonLock;
+SessionLibrary* SessionLibrary::sSingleton = NULL;
+
+SessionLibrary* SessionLibrary::get() {
+ Mutex::Autolock lock(sSingletonLock);
+
+ if (sSingleton == NULL) {
+ ALOGD("Instantiating Session Library Singleton.");
+ sSingleton = new SessionLibrary();
+ }
+
+ return sSingleton;
+}
+
+sp<Session> SessionLibrary::createSession() {
+ Mutex::Autolock lock(mSessionsLock);
+
+ char sessionIdRaw[16];
+ snprintf(sessionIdRaw, sizeof(sessionIdRaw), "%u", mNextSessionId);
+
+ mNextSessionId += 1;
+
+ std::vector<uint8_t> sessionId;
+ sessionId.insert(sessionId.end(), sessionIdRaw,
+ sessionIdRaw + sizeof(sessionIdRaw) / sizeof(uint8_t));
+
+ mSessions.insert(
+ std::pair<std::vector<uint8_t>, sp<Session>>(sessionId, new Session(sessionId)));
+ std::map<std::vector<uint8_t>, sp<Session>>::iterator itr = mSessions.find(sessionId);
+ if (itr != mSessions.end()) {
+ return itr->second;
+ } else {
+ return nullptr;
+ }
+}
+
+sp<Session> SessionLibrary::findSession(const std::vector<uint8_t>& sessionId) {
+ Mutex::Autolock lock(mSessionsLock);
+ std::map<std::vector<uint8_t>, sp<Session>>::iterator itr = mSessions.find(sessionId);
+ if (itr != mSessions.end()) {
+ return itr->second;
+ } else {
+ return nullptr;
+ }
+}
+
+void SessionLibrary::destroySession(const sp<Session>& session) {
+ Mutex::Autolock lock(mSessionsLock);
+ mSessions.erase(session->sessionId());
+}
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/include/ClearKeyUUID.h b/drm/mediadrm/plugins/clearkey/common/include/ClearKeyUUID.h
index fe10fba..8911024 100644
--- a/drm/mediadrm/plugins/clearkey/common/include/ClearKeyUUID.h
+++ b/drm/mediadrm/plugins/clearkey/common/include/ClearKeyUUID.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
@@ -13,9 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-#ifndef CLEARKEY_UUID_H_
-#define CLEARKEY_UUID_H_
+#pragma once
#include <array>
#include <cstdint>
@@ -27,6 +25,4 @@
std::vector<std::array<uint8_t, 16>> getSupportedCryptoSchemes();
-} // namespace clearkeydrm
-
-#endif // CLEARKEY_UUID_H_
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/AesCtrDecryptor.h b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/AesCtrDecryptor.h
new file mode 100644
index 0000000..dbf3098
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/AesCtrDecryptor.h
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <cstdint>
+
+#include "ClearKeyTypes.h"
+
+namespace clearkeydrm {
+
+class AesCtrDecryptor {
+ public:
+ AesCtrDecryptor() {}
+
+ CdmResponseType decrypt(const std::vector<uint8_t>& key, const Iv iv, const uint8_t* source,
+ uint8_t* destination,
+ const std::vector<int32_t>& clearDataLengths,
+ const std::vector<int32_t>& encryptedDataLengths,
+ size_t* bytesDecryptedOut);
+
+ private:
+ CLEARKEY_DISALLOW_COPY_AND_ASSIGN(AesCtrDecryptor);
+};
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/Base64.h b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/Base64.h
new file mode 100644
index 0000000..075d247
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/Base64.h
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include "Buffer.h"
+
+namespace clearkeydrm {
+
+struct Buffer;
+
+::android::sp<Buffer> decodeBase64(const std::string& s);
+
+void encodeBase64(const void* data, size_t size, std::string* out);
+
+void encodeBase64Url(const void* data, size_t size, std::string* out);
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/Buffer.h b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/Buffer.h
new file mode 100644
index 0000000..d41c4f3
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/Buffer.h
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <utils/RefBase.h>
+
+#include "ClearKeyTypes.h"
+
+namespace clearkeydrm {
+struct Buffer : public ::android::RefBase {
+ explicit Buffer(size_t capacity);
+
+ uint8_t* base() { return reinterpret_cast<uint8_t*>(mData); }
+ uint8_t* data() { return reinterpret_cast<uint8_t*>(mData) + mRangeOffset; }
+ size_t capacity() const { return mCapacity; }
+ size_t size() const { return mRangeLength; }
+ size_t offset() const { return mRangeOffset; }
+
+ protected:
+ virtual ~Buffer();
+
+ private:
+ void* mData;
+ size_t mCapacity;
+ size_t mRangeOffset;
+ size_t mRangeLength;
+
+ bool mOwnsData;
+
+ CLEARKEY_DISALLOW_COPY_AND_ASSIGN(Buffer);
+};
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/ClearKeyDrmProperties.h b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/ClearKeyDrmProperties.h
new file mode 100644
index 0000000..9a22633
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/ClearKeyDrmProperties.h
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <string>
+
+namespace clearkeydrm {
+static const std::string kVendorKey("vendor");
+static const std::string kVendorValue("Google");
+static const std::string kVersionKey("version");
+static const std::string kVersionValue("1.2");
+static const std::string kPluginDescriptionKey("description");
+static const std::string kPluginDescriptionValue("ClearKey CDM");
+static const std::string kAlgorithmsKey("algorithms");
+static const std::string kAlgorithmsValue("");
+static const std::string kListenerTestSupportKey("listenerTestSupport");
+static const std::string kListenerTestSupportValue("true");
+static const std::string kDrmErrorTestKey("drmErrorTest");
+static const std::string kDrmErrorTestValue("");
+static const std::string kResourceContentionValue("resourceContention");
+static const std::string kLostStateValue("lostState");
+static const std::string kFrameTooLargeValue("frameTooLarge");
+static const std::string kInvalidStateValue("invalidState");
+
+static const std::string kDeviceIdKey("deviceId");
+static const uint8_t kTestDeviceIdData[] = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+ 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
+
+// settable byte array property
+static const std::string kClientIdKey("clientId");
+
+// TODO stub out metrics for nw
+static const std::string kMetricsKey("metrics");
+static const uint8_t kMetricsData[] = {0};
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/ClearKeyTypes.h b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/ClearKeyTypes.h
new file mode 100644
index 0000000..0cc9511
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/ClearKeyTypes.h
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <map>
+#include <vector>
+
+namespace clearkeydrm {
+
+const uint8_t kBlockSize = 16; // AES_BLOCK_SIZE;
+typedef uint8_t KeyId[kBlockSize];
+typedef uint8_t Iv[kBlockSize];
+
+typedef std::map<std::vector<uint8_t>, std::vector<uint8_t>> KeyMap;
+
+#define CLEARKEY_DISALLOW_COPY_AND_ASSIGN(TypeName) \
+ TypeName(const TypeName&) = delete; \
+ void operator=(const TypeName&) = delete;
+
+#define CLEARKEY_DISALLOW_COPY_AND_ASSIGN_AND_NEW(TypeName) \
+ TypeName() = delete; \
+ TypeName(const TypeName&) = delete; \
+ void operator=(const TypeName&) = delete;
+
+enum CdmResponseType : int32_t {
+ OK = 0,
+ ERROR_NO_LICENSE = 1,
+ ERROR_SESSION_NOT_OPENED = 3,
+ ERROR_CANNOT_HANDLE = 4,
+ ERROR_INVALID_STATE = 5,
+ BAD_VALUE = 6,
+ ERROR_DECRYPT = 11,
+ ERROR_UNKNOWN = 12,
+ ERROR_INSUFFICIENT_SECURITY = 13,
+ ERROR_FRAME_TOO_LARGE = 14,
+ ERROR_SESSION_LOST_STATE = 15,
+ ERROR_RESOURCE_CONTENTION = 16,
+};
+
+enum CdmKeyType : int32_t {
+ KEY_TYPE_OFFLINE = 0,
+ KEY_TYPE_STREAMING = 1,
+ KEY_TYPE_RELEASE = 2,
+};
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/DeviceFiles.h b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/DeviceFiles.h
new file mode 100644
index 0000000..5698441
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/DeviceFiles.h
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "ClearKeyTypes.h"
+#include "MemoryFileSystem.h"
+
+namespace clearkeydrm {
+class OfflineFile;
+class DeviceFiles {
+ public:
+ typedef enum {
+ kLicenseStateUnknown,
+ kLicenseStateActive,
+ kLicenseStateReleasing,
+ } LicenseState;
+
+ DeviceFiles(){};
+ virtual ~DeviceFiles(){};
+
+ virtual bool StoreLicense(const std::string& keySetId, LicenseState state,
+ const std::string& keyResponse);
+
+ virtual bool RetrieveLicense(const std::string& key_set_id, LicenseState* state,
+ std::string* offlineLicense);
+
+ virtual bool LicenseExists(const std::string& keySetId);
+
+ virtual std::vector<std::string> ListLicenses() const;
+
+ virtual bool DeleteLicense(const std::string& keySetId);
+
+ virtual bool DeleteAllLicenses();
+
+ private:
+ bool FileExists(const std::string& path) const;
+ ssize_t GetFileSize(const std::string& fileName) const;
+ bool RemoveFile(const std::string& fileName);
+
+ bool RetrieveHashedFile(
+ const std::string& fileName,
+ OfflineFile* deSerializedFile);
+ bool StoreFileRaw(const std::string& fileName, const std::string& serializedFile);
+ bool StoreFileWithHash(const std::string& fileName, const std::string& serializedFile);
+
+ MemoryFileSystem mFileHandle;
+
+ CLEARKEY_DISALLOW_COPY_AND_ASSIGN(DeviceFiles);
+};
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/InitDataParser.h b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/InitDataParser.h
new file mode 100644
index 0000000..8ecc8e3
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/InitDataParser.h
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include "ClearKeyTypes.h"
+
+namespace clearkeydrm {
+
+class InitDataParser {
+ public:
+ InitDataParser() {}
+
+ CdmResponseType parse(const std::vector<uint8_t>& initData, const std::string& mimeType,
+ CdmKeyType keyType, std::vector<uint8_t>* licenseRequest);
+
+ private:
+ CLEARKEY_DISALLOW_COPY_AND_ASSIGN(InitDataParser);
+
+ CdmResponseType parsePssh(const std::vector<uint8_t>& initData,
+ std::vector<const uint8_t*>* keyIds);
+
+ std::string generateRequest(CdmKeyType keyType, const std::vector<const uint8_t*>& keyIds);
+};
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/JsonWebKey.h b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/JsonWebKey.h
new file mode 100644
index 0000000..6681553
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/JsonWebKey.h
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "jsmn.h"
+#include "ClearKeyTypes.h"
+
+namespace clearkeydrm {
+
+class JsonWebKey {
+ public:
+ JsonWebKey();
+ virtual ~JsonWebKey();
+
+ bool extractKeysFromJsonWebKeySet(const std::string& jsonWebKeySet, KeyMap* keys);
+
+ private:
+ std::vector<jsmntok_t> mJsmnTokens;
+ std::vector<std::string> mJsonObjects;
+ std::vector<std::string> mTokens;
+
+ bool decodeBase64String(const std::string& encodedText, std::vector<uint8_t>* decodedText);
+ bool findKey(const std::string& jsonObject, std::string* keyId, std::string* encodedKey);
+ void findValue(const std::string& key, std::string* value);
+ bool isJsonWebKeySet(const std::string& jsonObject) const;
+ bool parseJsonObject(const std::string& jsonObject, std::vector<std::string>* tokens);
+ bool parseJsonWebKeySet(const std::string& jsonWebKeySet,
+ std::vector<std::string>* jsonObjects);
+
+ CLEARKEY_DISALLOW_COPY_AND_ASSIGN(JsonWebKey);
+};
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/MemoryFileSystem.h b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/MemoryFileSystem.h
new file mode 100644
index 0000000..5642a0f
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/MemoryFileSystem.h
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <map>
+#include <string>
+
+#include "ClearKeyTypes.h"
+
+namespace clearkeydrm {
+
+// Using android file system requires clearkey plugin to update
+// its sepolicy. However, we are unable to update sepolicy for
+// older vendor partitions. To provide backward compatibility,
+// clearkey plugin implements a very simple file system in memory.
+// This memory file system does not support directory structure.
+class MemoryFileSystem {
+ public:
+ struct MemoryFile {
+ std::string fileName; // excludes path
+ std::string content;
+ size_t fileSize;
+
+ std::string getContent() const { return content; }
+ size_t getFileSize() const { return fileSize; }
+ void setContent(const std::string& file) { content = file; }
+ void setFileName(const std::string& name) { fileName = name; }
+ void setFileSize(size_t size) {
+ content.resize(size);
+ fileSize = size;
+ }
+ };
+
+ MemoryFileSystem(){};
+ virtual ~MemoryFileSystem(){};
+
+ bool FileExists(const std::string& fileName) const;
+ ssize_t GetFileSize(const std::string& fileName) const;
+ std::vector<std::string> ListFiles() const;
+ size_t Read(const std::string& pathName, std::string* buffer);
+ bool RemoveAllFiles();
+ bool RemoveFile(const std::string& fileName);
+ size_t Write(const std::string& pathName, const MemoryFile& memoryFile);
+
+ private:
+ // License file name is made up of a unique keySetId, therefore,
+ // the filename can be used as the key to locate licenses in the
+ // memory file system.
+ std::map<std::string, MemoryFile> mMemoryFileSystem;
+
+ std::string GetFileName(const std::string& path);
+
+ CLEARKEY_DISALLOW_COPY_AND_ASSIGN(MemoryFileSystem);
+};
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/MimeTypeStdStr.h b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/MimeTypeStdStr.h
new file mode 100644
index 0000000..dea2974
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/MimeTypeStdStr.h
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <string>
+
+namespace {
+const std::string kCencInitDataFormat("cenc");
+const std::string kIsoBmffAudioMimeType("audio/mp4");
+const std::string kIsoBmffVideoMimeType("video/mp4");
+const std::string kWebmInitDataFormat("webm");
+const std::string kWebmAudioMimeType("audio/webm");
+const std::string kWebmVideoMimeType("video/webm");
+} // namespace
diff --git a/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/Session.h b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/Session.h
new file mode 100644
index 0000000..e2d4e32
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/Session.h
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <utils/Mutex.h>
+#include <utils/RefBase.h>
+
+#include <cstdint>
+#include <vector>
+
+#include "ClearKeyTypes.h"
+
+namespace clearkeydrm {
+
+class Session : public ::android::RefBase {
+ public:
+ explicit Session(const std::vector<uint8_t>& sessionId)
+ : mSessionId(sessionId), mMockError(clearkeydrm::OK) {}
+ virtual ~Session() {}
+
+ const std::vector<uint8_t>& sessionId() const { return mSessionId; }
+
+ CdmResponseType getKeyRequest(const std::vector<uint8_t>& initDataType,
+ const std::string& mimeType,
+ CdmKeyType keyType,
+ std::vector<uint8_t>* keyRequest) const;
+
+ CdmResponseType provideKeyResponse(const std::vector<uint8_t>& response);
+
+ CdmResponseType decrypt(const KeyId keyId, const Iv iv, const uint8_t* srcPtr, uint8_t* dstPtr,
+ const std::vector<int32_t>& clearDataLengths,
+ const std::vector<int32_t>& encryptedDataLengths,
+ size_t* bytesDecryptedOut);
+
+ void setMockError(CdmResponseType error) { mMockError = error; }
+ CdmResponseType getMockError() const { return mMockError; }
+
+ private:
+ CLEARKEY_DISALLOW_COPY_AND_ASSIGN(Session);
+
+ const std::vector<uint8_t> mSessionId;
+ KeyMap mKeyMap;
+ ::android::Mutex mMapLock;
+
+ // For mocking error return scenarios
+ CdmResponseType mMockError;
+};
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/SessionLibrary.h b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/SessionLibrary.h
new file mode 100644
index 0000000..987e328
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/SessionLibrary.h
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <utils/Mutex.h>
+#include <utils/RefBase.h>
+
+#include "ClearKeyTypes.h"
+#include "Session.h"
+
+namespace clearkeydrm {
+
+class SessionLibrary : public ::android::RefBase {
+ public:
+ static SessionLibrary* get();
+
+ ::android::sp<Session> createSession();
+
+ ::android::sp<Session> findSession(const std::vector<uint8_t>& sessionId);
+
+ void destroySession(const ::android::sp<Session>& session);
+
+ size_t numOpenSessions() const { return mSessions.size(); }
+
+ private:
+ CLEARKEY_DISALLOW_COPY_AND_ASSIGN(SessionLibrary);
+
+ SessionLibrary() : mNextSessionId(1) {}
+
+ static ::android::Mutex sSingletonLock;
+ static SessionLibrary* sSingleton;
+
+ ::android::Mutex mSessionsLock;
+ uint32_t mNextSessionId;
+ std::map<std::vector<uint8_t>, ::android::sp<Session>> mSessions;
+};
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/common/protos/DeviceFiles.proto b/drm/mediadrm/plugins/clearkey/common/protos/DeviceFiles.proto
new file mode 100644
index 0000000..2d98656
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/common/protos/DeviceFiles.proto
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+syntax = "proto2";
+
+package clearkeydrm;
+
+// need this if we are using libprotobuf-cpp-2.3.0-lite
+option optimize_for = LITE_RUNTIME;
+
+message License {
+ enum LicenseState {
+ ACTIVE = 1;
+ RELEASING = 2;
+ }
+
+ optional LicenseState state = 1;
+ optional bytes license = 2;
+}
+
+message OfflineFile {
+ enum FileType {
+ LICENSE = 1;
+ }
+
+ enum FileVersion {
+ VERSION_1 = 1;
+ }
+
+ optional FileType type = 1;
+ optional FileVersion version = 2 [default = VERSION_1];
+ optional License license = 3;
+
+}
+
+message HashedFile {
+ optional bytes file = 1;
+ // A raw (not hex-encoded) SHA256, taken over the bytes of 'file'.
+ optional bytes hash = 2;
+}
diff --git a/drm/mediadrm/plugins/clearkey/hidl/Android.bp b/drm/mediadrm/plugins/clearkey/hidl/Android.bp
index 6c68532..02ac943 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/Android.bp
+++ b/drm/mediadrm/plugins/clearkey/hidl/Android.bp
@@ -93,6 +93,11 @@
srcs: ["protos/DeviceFiles.proto"],
}
+cc_library {
+ name: "libclearkeyhidl",
+ defaults: ["clearkey_service_defaults"],
+}
+
cc_binary {
name: "android.hardware.drm@1.2-service.clearkey",
defaults: ["clearkey_service_defaults"],
@@ -126,3 +131,37 @@
init_rc: ["android.hardware.drm@1.4-service-lazy.clearkey.rc"],
vintf_fragments: ["manifest_android.hardware.drm@1.4-service.clearkey.xml"],
}
+
+cc_fuzz {
+ name: "clearkeyV1.4_fuzzer",
+ vendor: true,
+ srcs: [
+ "fuzzer/clearkeyV1.4_fuzzer.cpp",
+ ],
+ static_libs: [
+ "libclearkeyhidl",
+ "libclearkeycommon",
+ "libclearkeydevicefiles-protos",
+ "libjsmn",
+ "libprotobuf-cpp-lite",
+ "libutils",
+ ],
+ shared_libs: [
+ "android.hidl.allocator@1.0",
+ "android.hardware.drm@1.0",
+ "android.hardware.drm@1.1",
+ "android.hardware.drm@1.2",
+ "android.hardware.drm@1.3",
+ "android.hardware.drm@1.4",
+ "libcrypto",
+ "libhidlbase",
+ "libhidlmemory",
+ "liblog",
+ ],
+ fuzz_config: {
+ cc: [
+ "android-media-fuzzing-reports@google.com",
+ ],
+ componentid: 155276,
+ },
+}
diff --git a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
index 0cd9375..32d7723 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
@@ -187,7 +187,7 @@
return Status_V1_2::ERROR_DRM_CANNOT_HANDLE;
}
- *defaultUrl = "";
+ *defaultUrl = "https://default.url";
*keyRequestType = KeyRequestType_V1_1::UNKNOWN;
*request = std::vector<uint8_t>();
diff --git a/drm/mediadrm/plugins/clearkey/hidl/fuzzer/README.md b/drm/mediadrm/plugins/clearkey/hidl/fuzzer/README.md
new file mode 100644
index 0000000..cb45460
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/fuzzer/README.md
@@ -0,0 +1,52 @@
+# Fuzzer for android.hardware.drm@1.4-service.clearkey
+
+## Plugin Design Considerations
+The fuzzer plugin for android.hardware.drm@1.4-service.clearkey is designed based on the understanding of the
+source code 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.
+
+android.hardware.drm@1.4-service.clearkey supports the following parameters:
+1. Security Level (parameter name: `securityLevel`)
+2. Mime Type (parameter name: `mimeType`)
+3. Key Type (parameter name: `keyType`)
+4. Crypto Mode (parameter name: `cryptoMode`)
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+| `securityLevel` | 0.`SecurityLevel::UNKNOWN` 1.`SecurityLevel::SW_SECURE_CRYPTO` 2.`SecurityLevel::SW_SECURE_DECODE` 3.`SecurityLevel::HW_SECURE_CRYPTO` 4.`SecurityLevel::HW_SECURE_DECODE` 5.`SecurityLevel::HW_SECURE_ALL`| Value obtained from FuzzedDataProvider in the range 0 to 5|
+| `mimeType` | 0.`video/mp4` 1.`video/mpeg` 2.`video/x-flv` 3.`video/mj2` 4.`video/3gp2` 5.`video/3gpp` 6.`video/3gpp2` 7.`audio/mp4` 8.`audio/mpeg` 9.`audio/aac` 10.`audio/3gp2` 11.`audio/3gpp` 12.`audio/3gpp2` 13.`audio/webm` 14.`video/webm` 15.`webm` 16.`cenc` 17.`video/unknown` 18.`audio/unknown`| Value obtained from FuzzedDataProvider in the range 0 to 18|
+| `keyType` | 0.`KeyType::OFFLINE` 1.`KeyType::STREAMING` 2.`KeyType::RELEASE` | Value obtained from FuzzedDataProvider in the range 0 to 2|
+| `cryptoMode` | 0.`Mode::UNENCRYPTED` 1.`Mode::AES_CTR` 2.`Mode::AES_CBC_CTS` 3.`Mode::AES_CBC` | Value obtained from FuzzedDataProvider in the range 0 to 3|
+
+This also ensures that the plugin is always deterministic for any given input.
+
+##### Maximize utilization of input data
+The plugin feeds the entire input data to the module.
+This ensures that the plugin tolerates any kind of input (empty, huge,
+malformed, etc) and doesnt `exit()` on any input and thereby increasing the
+chance of identifying vulnerabilities.
+
+## Build
+
+This describes steps to build clearkeyV1.4_fuzzer binary.
+
+### Android
+
+#### Steps to build
+Build the fuzzer
+```
+ $ mm -j$(nproc) clearkeyV1.4_fuzzer
+```
+#### Steps to run
+To run on device
+```
+ $ adb sync data
+ $ adb shell /data/fuzz/${TARGET_ARCH}/clearkeyV1.4_fuzzer/vendor/hw/clearkeyV1.4_fuzzer
+```
+
+## References:
+ * http://llvm.org/docs/LibFuzzer.html
+ * https://github.com/google/oss-fuzz
diff --git a/drm/mediadrm/plugins/clearkey/hidl/fuzzer/clearkeyV1.4_fuzzer.cpp b/drm/mediadrm/plugins/clearkey/hidl/fuzzer/clearkeyV1.4_fuzzer.cpp
new file mode 100644
index 0000000..afe0e6c
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/fuzzer/clearkeyV1.4_fuzzer.cpp
@@ -0,0 +1,719 @@
+/*
+ * 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.
+ *
+ */
+
+#include <include/CreatePluginFactories.h>
+
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <hidlmemory/mapping.h>
+#include <include/ClearKeyDrmProperties.h>
+#include <include/CryptoFactory.h>
+#include <include/CryptoPlugin.h>
+#include <include/DrmPlugin.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+namespace drm = ::android::hardware::drm;
+using namespace std;
+using namespace android;
+using ::android::sp;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hidl::allocator::V1_0::IAllocator;
+using ::android::hidl::memory::V1_0::IMemory;
+using drm::V1_0::BufferType;
+using drm::V1_0::DestinationBuffer;
+using drm::V1_0::EventType;
+using drm::V1_0::ICryptoPlugin;
+using drm::V1_0::IDrmPlugin;
+using drm::V1_0::IDrmPluginListener;
+using drm::V1_0::KeyedVector;
+using drm::V1_0::KeyStatus;
+using drm::V1_0::KeyStatusType;
+using drm::V1_0::KeyType;
+using drm::V1_0::Mode;
+using drm::V1_0::Pattern;
+using drm::V1_0::SecureStop;
+using drm::V1_0::SharedBuffer;
+using drm::V1_0::Status;
+using drm::V1_0::SubSample;
+using drm::V1_1::DrmMetricGroup;
+using drm::V1_1::HdcpLevel;
+using drm::V1_1::SecureStopRelease;
+using drm::V1_1::SecurityLevel;
+using drm::V1_2::KeySetId;
+using drm::V1_2::OfflineLicenseState;
+using drm::V1_4::clearkey::ICryptoFactory;
+using drm::V1_4::clearkey::IDrmFactory;
+using drm::V1_4::clearkey::kAlgorithmsKey;
+using drm::V1_4::clearkey::kClientIdKey;
+using drm::V1_4::clearkey::kDeviceIdKey;
+using drm::V1_4::clearkey::kDrmErrorTestKey;
+using drm::V1_4::clearkey::kListenerTestSupportKey;
+using drm::V1_4::clearkey::kMetricsKey;
+using drm::V1_4::clearkey::kPluginDescriptionKey;
+using drm::V1_4::clearkey::kVendorKey;
+using drm::V1_4::clearkey::kVersionKey;
+
+typedef ::android::hardware::hidl_vec<uint8_t> SessionId;
+typedef ::android::hardware::hidl_vec<uint8_t> SecureStopId;
+
+static const uint8_t kInvalidUUID[] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60,
+ 0x70, 0x80, 0x10, 0x20, 0x30, 0x40,
+ 0x50, 0x60, 0x70, 0x80};
+
+static const uint8_t kClearKeyUUID[] = {0xE2, 0x71, 0x9D, 0x58, 0xA9, 0x85,
+ 0xB3, 0xC9, 0x78, 0x1A, 0xB0, 0x30,
+ 0xAF, 0x78, 0xD3, 0x0E};
+
+const SecurityLevel kSecurityLevel[] = {
+ SecurityLevel::UNKNOWN, SecurityLevel::SW_SECURE_CRYPTO,
+ SecurityLevel::SW_SECURE_DECODE, SecurityLevel::HW_SECURE_CRYPTO,
+ SecurityLevel::HW_SECURE_DECODE, SecurityLevel::HW_SECURE_ALL};
+
+const char *kMimeType[] = {
+ "video/mp4", "video/mpeg", "video/x-flv", "video/mj2", "video/3gp2",
+ "video/3gpp", "video/3gpp2", "audio/mp4", "audio/mpeg", "audio/aac",
+ "audio/3gp2", "audio/3gpp", "audio/3gpp2", "audio/webm", "video/webm",
+ "webm", "cenc", "video/unknown", "audio/unknown"};
+
+const char *kCipherAlgorithm[] = {"AES/CBC/NoPadding", ""};
+
+const char *kMacAlgorithm[] = {"HmacSHA256", ""};
+
+const char *kRSAAlgorithm[] = {"RSASSA-PSS-SHA1", ""};
+
+const std::string kProperty[] = {kVendorKey,
+ kVersionKey,
+ kPluginDescriptionKey,
+ kAlgorithmsKey,
+ kListenerTestSupportKey,
+ kDrmErrorTestKey,
+ kDeviceIdKey,
+ kClientIdKey,
+ kMetricsKey,
+ "placeholder"};
+
+const KeyType kKeyType[] = {KeyType::OFFLINE, KeyType::STREAMING,
+ KeyType::RELEASE};
+
+const Mode kCryptoMode[] = {Mode::UNENCRYPTED, Mode::AES_CTR, Mode::AES_CBC_CTS,
+ Mode::AES_CBC};
+
+const hidl_vec<uint8_t> validInitData = {
+ // BMFF box header (4 bytes size + 'pssh')
+ 0x00, 0x00, 0x00, 0x34, 0x70, 0x73, 0x73, 0x68,
+ // full box header (version = 1 flags = 0)
+ 0x01, 0x00, 0x00, 0x00,
+ // system id
+ 0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2, 0x4d, 0x02, 0xac, 0xe3, 0x3c, 0x1e,
+ 0x52, 0xe2, 0xfb, 0x4b,
+ // number of key ids
+ 0x00, 0x00, 0x00, 0x01,
+ // key id
+ 0x60, 0x06, 0x1e, 0x01, 0x7e, 0x47, 0x7e, 0x87, 0x7e, 0x57, 0xd0, 0x0d,
+ 0x1e, 0xd0, 0x0d, 0x1e,
+ // size of data, must be zero
+ 0x00, 0x00, 0x00, 0x00};
+
+const hidl_vec<uint8_t> validKeyResponse = {
+ 0x7b, 0x22, 0x6b, 0x65, 0x79, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22,
+ 0x6b, 0x74, 0x79, 0x22, 0x3a, 0x22, 0x6f, 0x63, 0x74, 0x22, 0x2c,
+ 0x22, 0x6b, 0x69, 0x64, 0x22, 0x3a, 0x22, 0x59, 0x41, 0x59, 0x65,
+ 0x41, 0x58, 0x35, 0x48, 0x66, 0x6f, 0x64, 0x2d, 0x56, 0x39, 0x41,
+ 0x4e, 0x48, 0x74, 0x41, 0x4e, 0x48, 0x67, 0x22, 0x2c, 0x22, 0x6b,
+ 0x22, 0x3a, 0x22, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x54, 0x65,
+ 0x73, 0x74, 0x4b, 0x65, 0x79, 0x42, 0x61, 0x73, 0x65, 0x36, 0x34,
+ 0x67, 0x67, 0x67, 0x22, 0x7d, 0x5d, 0x7d, 0x0a};
+
+const size_t kAESBlockSize = 16;
+const size_t kMaxStringLength = 100;
+const size_t kMaxSubSamples = 10;
+const size_t kMaxNumBytes = 1000;
+const size_t kSegmentIndex = 0;
+
+template <typename T, size_t size>
+T getValueFromArray(FuzzedDataProvider *fdp, const T (&arr)[size]) {
+ return arr[fdp->ConsumeIntegralInRange<int32_t>(0, size - 1)];
+}
+
+class TestDrmPluginListener : public IDrmPluginListener {
+public:
+ TestDrmPluginListener() {}
+ virtual ~TestDrmPluginListener() {}
+
+ virtual Return<void> sendEvent(EventType /*eventType*/,
+ const hidl_vec<uint8_t> & /*sessionId*/,
+ const hidl_vec<uint8_t> & /*data*/) override {
+ return Return<void>();
+ }
+
+ virtual Return<void>
+ sendExpirationUpdate(const hidl_vec<uint8_t> & /*sessionId*/,
+ int64_t /*expiryTimeInMS*/) override {
+ return Return<void>();
+ }
+
+ virtual Return<void>
+ sendKeysChange(const hidl_vec<uint8_t> & /*sessionId*/,
+ const hidl_vec<KeyStatus> & /*keyStatusList*/,
+ bool /*hasNewUsableKey*/) override {
+ return Return<void>();
+ }
+};
+
+class ClearKeyFuzzer {
+public:
+ ~ClearKeyFuzzer() { deInit(); }
+ bool init();
+ void process(const uint8_t *data, size_t size);
+
+private:
+ void deInit();
+ void invokeDrmPlugin(const uint8_t *data, size_t size);
+ void invokeCryptoPlugin(const uint8_t *data);
+ void invokeDrm(const uint8_t *data, size_t size);
+ void invokeCrypto(const uint8_t *data);
+ void invokeDrmDecryptEncryptAPI(const uint8_t *data, size_t size);
+ bool invokeDrmFactory();
+ bool invokeCryptoFactory();
+ void invokeDrmV1_4API();
+ void invokeDrmSetAlgorithmAPI();
+ void invokeDrmPropertyAPI();
+ void invokeDrmSecureStopAPI();
+ void invokeDrmOfflineLicenseAPI(const uint8_t *data, size_t size);
+ SessionId getSessionId();
+ SecureStopRelease makeSecureRelease(const SecureStop &stop);
+ sp<IDrmFactory> mDrmFactory = nullptr;
+ sp<ICryptoFactory> mCryptoFactory = nullptr;
+ sp<IDrmPlugin> mDrmPlugin = nullptr;
+ sp<drm::V1_1::IDrmPlugin> mDrmPluginV1_1 = nullptr;
+ sp<drm::V1_2::IDrmPlugin> mDrmPluginV1_2 = nullptr;
+ sp<drm::V1_4::IDrmPlugin> mDrmPluginV1_4 = nullptr;
+ sp<drm::V1_4::ICryptoPlugin> mCryptoPluginV1_4 = nullptr;
+ sp<ICryptoPlugin> mCryptoPlugin = nullptr;
+ FuzzedDataProvider *mFDP = nullptr;
+ SessionId mSessionId = {};
+ SessionId mSessionIdV1 = {};
+};
+
+void ClearKeyFuzzer::deInit() {
+ if (mDrmPluginV1_1) {
+ mDrmPluginV1_1->closeSession(mSessionIdV1);
+ }
+ if (mDrmPluginV1_2) {
+ mDrmPluginV1_2->closeSession(mSessionId);
+ }
+ mDrmFactory.clear();
+ mCryptoFactory.clear();
+ mDrmPlugin.clear();
+ mDrmPluginV1_1.clear();
+ mDrmPluginV1_2.clear();
+ mDrmPluginV1_4.clear();
+ mCryptoPlugin.clear();
+ mCryptoPluginV1_4.clear();
+ mSessionId = {};
+ mSessionIdV1 = {};
+}
+
+void ClearKeyFuzzer::invokeDrmV1_4API() {
+ mDrmPluginV1_4->requiresSecureDecoderDefault(
+ getValueFromArray(mFDP, kMimeType));
+ mDrmPluginV1_4->requiresSecureDecoder(
+ getValueFromArray(mFDP, kMimeType),
+ getValueFromArray(mFDP, kSecurityLevel));
+ mDrmPluginV1_4->setPlaybackId(
+ mSessionId, mFDP->ConsumeRandomLengthString(kMaxStringLength).c_str());
+ drm::V1_4::IDrmPlugin::getLogMessages_cb cb =
+ [&]([[maybe_unused]] drm::V1_4::Status status,
+ [[maybe_unused]] hidl_vec<drm::V1_4::LogMessage> logs) {};
+ mDrmPluginV1_4->getLogMessages(cb);
+}
+
+void ClearKeyFuzzer::invokeDrmSetAlgorithmAPI() {
+ const hidl_string cipherAlgo =
+ mFDP->ConsumeBool()
+ ? mFDP->ConsumeRandomLengthString(kMaxStringLength).c_str()
+ : hidl_string(kCipherAlgorithm[mFDP->ConsumeBool()]);
+ mDrmPluginV1_2->setCipherAlgorithm(mSessionId, cipherAlgo);
+
+ const hidl_string macAlgo =
+ mFDP->ConsumeBool()
+ ? mFDP->ConsumeRandomLengthString(kMaxStringLength).c_str()
+ : hidl_string(kMacAlgorithm[mFDP->ConsumeBool()]);
+ mDrmPluginV1_2->setMacAlgorithm(mSessionId, macAlgo);
+}
+
+void ClearKeyFuzzer::invokeDrmPropertyAPI() {
+ mDrmPluginV1_2->setPropertyString(
+ hidl_string(getValueFromArray(mFDP, kProperty)), hidl_string("value"));
+
+ hidl_string stringValue;
+ mDrmPluginV1_2->getPropertyString(
+ getValueFromArray(mFDP, kProperty),
+ [&](Status status, const hidl_string &hValue) {
+ if (status == Status::OK) {
+ stringValue = hValue;
+ }
+ });
+
+ hidl_vec<uint8_t> value = {};
+ mDrmPluginV1_2->setPropertyByteArray(
+ hidl_string(getValueFromArray(mFDP, kProperty)), value);
+
+ hidl_vec<uint8_t> byteValue;
+ mDrmPluginV1_2->getPropertyByteArray(
+ getValueFromArray(mFDP, kProperty),
+ [&](Status status, const hidl_vec<uint8_t> &hValue) {
+ if (status == Status::OK) {
+ byteValue = hValue;
+ }
+ });
+}
+
+SessionId ClearKeyFuzzer::getSessionId() {
+ SessionId emptySessionId = {};
+ return mFDP->ConsumeBool() ? mSessionId : emptySessionId;
+}
+
+void ClearKeyFuzzer::invokeDrmDecryptEncryptAPI(const uint8_t *data,
+ size_t size) {
+ uint32_t currSessions, maximumSessions;
+ mDrmPluginV1_2->getNumberOfSessions(
+ [&](Status status, uint32_t hCurrentSessions, uint32_t hMaxSessions) {
+ if (status == Status::OK) {
+ currSessions = hCurrentSessions;
+ maximumSessions = hMaxSessions;
+ }
+ });
+
+ HdcpLevel connected, maximum;
+ mDrmPluginV1_2->getHdcpLevels([&](Status status,
+ const HdcpLevel &hConnectedLevel,
+ const HdcpLevel &hMaxLevel) {
+ if (status == Status::OK) {
+ connected = hConnectedLevel;
+ maximum = hMaxLevel;
+ }
+ });
+
+ drm::V1_2::HdcpLevel connectedV1_2, maximumV1_2;
+ mDrmPluginV1_2->getHdcpLevels_1_2(
+ [&](drm::V1_2::Status status, const drm::V1_2::HdcpLevel &connectedLevel,
+ const drm::V1_2::HdcpLevel &maxLevel) {
+ if (status == drm::V1_2::Status::OK) {
+ connectedV1_2 = connectedLevel;
+ maximumV1_2 = maxLevel;
+ }
+ });
+
+ SecurityLevel securityLevel;
+ mDrmPluginV1_2->getSecurityLevel(mSessionId,
+ [&](Status status, SecurityLevel hLevel) {
+ if (status == Status::OK) {
+ securityLevel = hLevel;
+ }
+ });
+
+ hidl_vec<DrmMetricGroup> metrics;
+ mDrmPluginV1_2->getMetrics(
+ [&](Status status, hidl_vec<DrmMetricGroup> hMetricGroups) {
+ if (status == Status::OK) {
+ metrics = hMetricGroups;
+ }
+ });
+
+ hidl_string certificateType;
+ hidl_string certificateAuthority;
+ mDrmPluginV1_2->getProvisionRequest(certificateType, certificateAuthority,
+ [&]([[maybe_unused]] Status status,
+ const hidl_vec<uint8_t> &,
+ const hidl_string &) {});
+
+ mDrmPluginV1_2->getProvisionRequest_1_2(
+ certificateType, certificateAuthority,
+ [&]([[maybe_unused]] drm::V1_2::Status status, const hidl_vec<uint8_t> &,
+ const hidl_string &) {});
+
+ hidl_vec<uint8_t> response;
+ mDrmPluginV1_2->provideProvisionResponse(
+ response, [&]([[maybe_unused]] Status status, const hidl_vec<uint8_t> &,
+ const hidl_vec<uint8_t> &) {});
+
+ hidl_vec<uint8_t> initData = {};
+ if (mFDP->ConsumeBool()) {
+ initData = validInitData;
+ } else {
+ initData.setToExternal(const_cast<uint8_t *>(data), kAESBlockSize);
+ }
+ hidl_string mimeType = getValueFromArray(mFDP, kMimeType);
+ KeyType keyType = mFDP->ConsumeBool()
+ ? static_cast<KeyType>(mFDP->ConsumeIntegral<size_t>())
+ : getValueFromArray(mFDP, kKeyType);
+ KeyedVector optionalParameters;
+ mDrmPluginV1_2->getKeyRequest_1_2(
+ mSessionId, initData, mimeType, keyType, optionalParameters,
+ [&]([[maybe_unused]] drm::V1_2::Status status, const hidl_vec<uint8_t> &,
+ drm::V1_1::KeyRequestType, const hidl_string &) {});
+ mDrmPluginV1_1->getKeyRequest_1_1(
+ mSessionIdV1, initData, mimeType, keyType, optionalParameters,
+ [&]([[maybe_unused]] drm::V1_0::Status status, const hidl_vec<uint8_t> &,
+ drm::V1_1::KeyRequestType, const hidl_string &) {});
+ hidl_vec<uint8_t> emptyInitData = {};
+ mDrmPlugin->getKeyRequest(
+ mSessionId, mFDP->ConsumeBool() ? initData : emptyInitData, mimeType,
+ keyType, optionalParameters,
+ [&]([[maybe_unused]] drm::V1_0::Status status, const hidl_vec<uint8_t> &,
+ drm::V1_0::KeyRequestType, const hidl_string &) {});
+
+ hidl_vec<uint8_t> keyResponse = {};
+ if (mFDP->ConsumeBool()) {
+ keyResponse = validKeyResponse;
+ } else {
+ keyResponse.setToExternal(const_cast<uint8_t *>(data), size);
+ }
+ hidl_vec<uint8_t> keySetId;
+ hidl_vec<uint8_t> emptyKeyResponse = {};
+ mDrmPluginV1_2->provideKeyResponse(
+ getSessionId(), mFDP->ConsumeBool() ? keyResponse : emptyKeyResponse,
+ [&](Status status, const hidl_vec<uint8_t> &hKeySetId) {
+ if (status == Status::OK) {
+ keySetId = hKeySetId;
+ }
+ });
+
+ mDrmPluginV1_2->restoreKeys(getSessionId(), keySetId);
+
+ mDrmPluginV1_2->queryKeyStatus(
+ getSessionId(),
+ [&]([[maybe_unused]] Status status, KeyedVector /* info */) {});
+
+ hidl_vec<uint8_t> keyId, input, iv;
+ keyId.setToExternal(const_cast<uint8_t *>(data), size);
+ input.setToExternal(const_cast<uint8_t *>(data), size);
+ iv.setToExternal(const_cast<uint8_t *>(data), size);
+ mDrmPluginV1_2->encrypt(
+ getSessionId(), keyId, input, iv,
+ [&]([[maybe_unused]] Status status, const hidl_vec<uint8_t> &) {});
+
+ mDrmPluginV1_2->decrypt(
+ getSessionId(), keyId, input, iv,
+ [&]([[maybe_unused]] Status status, const hidl_vec<uint8_t> &) {});
+
+ hidl_vec<uint8_t> message;
+ message.setToExternal(const_cast<uint8_t *>(data), size);
+ mDrmPluginV1_2->sign(
+ getSessionId(), keyId, message,
+ [&]([[maybe_unused]] Status status, const hidl_vec<uint8_t> &) {});
+
+ hidl_vec<uint8_t> signature;
+ signature.setToExternal(const_cast<uint8_t *>(data), size);
+ mDrmPluginV1_2->verify(getSessionId(), keyId, message, signature,
+ [&]([[maybe_unused]] Status status, bool) {});
+
+ hidl_vec<uint8_t> wrappedKey;
+ signature.setToExternal(const_cast<uint8_t *>(data), size);
+ mDrmPluginV1_2->signRSA(
+ getSessionId(), kRSAAlgorithm[mFDP->ConsumeBool()], message, wrappedKey,
+ [&]([[maybe_unused]] Status status, const hidl_vec<uint8_t> &) {});
+
+ mDrmPluginV1_2->removeKeys(getSessionId());
+}
+
+/**
+ * Helper function to create a secure release message for
+ * a secure stop. The clearkey secure stop release format
+ * is just a count followed by the secure stop opaque data.
+ */
+SecureStopRelease ClearKeyFuzzer::makeSecureRelease(const SecureStop &stop) {
+ std::vector<uint8_t> stopData = stop.opaqueData;
+ std::vector<uint8_t> buffer;
+ std::string count = "0001";
+
+ auto it = buffer.insert(buffer.begin(), count.begin(), count.end());
+ buffer.insert(it + count.size(), stopData.begin(), stopData.end());
+ SecureStopRelease release = {.opaqueData = hidl_vec<uint8_t>(buffer)};
+ return release;
+}
+
+void ClearKeyFuzzer::invokeDrmSecureStopAPI() {
+ SecureStopId ssid;
+ mDrmPluginV1_2->getSecureStop(
+ ssid, [&]([[maybe_unused]] Status status, const SecureStop &) {});
+
+ mDrmPluginV1_2->getSecureStopIds(
+ [&]([[maybe_unused]] Status status,
+ [[maybe_unused]] const hidl_vec<SecureStopId> &secureStopIds) {});
+
+ SecureStopRelease release;
+ mDrmPluginV1_2->getSecureStops(
+ [&]([[maybe_unused]] Status status, const hidl_vec<SecureStop> &stops) {
+ if (stops.size() > 0) {
+ release = makeSecureRelease(
+ stops[mFDP->ConsumeIntegralInRange<size_t>(0, stops.size() - 1)]);
+ }
+ });
+
+ mDrmPluginV1_2->releaseSecureStops(release);
+
+ mDrmPluginV1_2->removeSecureStop(ssid);
+
+ mDrmPluginV1_2->removeAllSecureStops();
+
+ mDrmPluginV1_2->releaseSecureStop(ssid);
+
+ mDrmPluginV1_2->releaseAllSecureStops();
+}
+
+void ClearKeyFuzzer::invokeDrmOfflineLicenseAPI(const uint8_t *data,
+ size_t size) {
+ hidl_vec<KeySetId> keySetIds = {};
+ mDrmPluginV1_2->getOfflineLicenseKeySetIds(
+ [&](Status status, const hidl_vec<KeySetId> &hKeySetIds) {
+ if (status == Status::OK) {
+ keySetIds = hKeySetIds;
+ }
+ });
+
+ OfflineLicenseState licenseState;
+ KeySetId keySetId = {};
+ if (keySetIds.size() > 0) {
+ keySetId = keySetIds[mFDP->ConsumeIntegralInRange<size_t>(
+ 0, keySetIds.size() - 1)];
+ } else {
+ keySetId.setToExternal(const_cast<uint8_t *>(data), size);
+ }
+ mDrmPluginV1_2->getOfflineLicenseState(
+ keySetId, [&](Status status, OfflineLicenseState hLicenseState) {
+ if (status == Status::OK) {
+ licenseState = hLicenseState;
+ }
+ });
+
+ mDrmPluginV1_2->removeOfflineLicense(keySetId);
+}
+
+void ClearKeyFuzzer::invokeDrmPlugin(const uint8_t *data, size_t size) {
+ SecurityLevel secLevel =
+ mFDP->ConsumeBool()
+ ? getValueFromArray(mFDP, kSecurityLevel)
+ : static_cast<SecurityLevel>(mFDP->ConsumeIntegral<uint32_t>());
+ mDrmPluginV1_1->openSession_1_1(
+ secLevel, [&]([[maybe_unused]] Status status, const SessionId &id) {
+ mSessionIdV1 = id;
+ });
+ mDrmPluginV1_2->openSession([&]([[maybe_unused]] Status status,
+ const SessionId &id) { mSessionId = id; });
+
+ sp<TestDrmPluginListener> listener = new TestDrmPluginListener();
+ mDrmPluginV1_2->setListener(listener);
+ const hidl_vec<KeyStatus> keyStatusList = {
+ {{1}, KeyStatusType::USABLE},
+ {{2}, KeyStatusType::EXPIRED},
+ {{3}, KeyStatusType::OUTPUTNOTALLOWED},
+ {{4}, KeyStatusType::STATUSPENDING},
+ {{5}, KeyStatusType::INTERNALERROR},
+ };
+ mDrmPluginV1_2->sendKeysChange(mSessionId, keyStatusList, true);
+
+ invokeDrmV1_4API();
+ invokeDrmSetAlgorithmAPI();
+ invokeDrmPropertyAPI();
+ invokeDrmDecryptEncryptAPI(data, size);
+ invokeDrmSecureStopAPI();
+ invokeDrmOfflineLicenseAPI(data, size);
+}
+
+void ClearKeyFuzzer::invokeCryptoPlugin(const uint8_t *data) {
+ mCryptoPlugin->requiresSecureDecoderComponent(
+ getValueFromArray(mFDP, kMimeType));
+
+ const uint32_t width = mFDP->ConsumeIntegral<uint32_t>();
+ const uint32_t height = mFDP->ConsumeIntegral<uint32_t>();
+ mCryptoPlugin->notifyResolution(width, height);
+
+ mCryptoPlugin->setMediaDrmSession(mSessionId);
+
+ size_t totalSize = 0;
+ const size_t numSubSamples =
+ mFDP->ConsumeIntegralInRange<size_t>(1, kMaxSubSamples);
+
+ const Pattern pattern = {0, 0};
+ hidl_vec<SubSample> subSamples;
+ subSamples.resize(numSubSamples);
+
+ for (size_t i = 0; i < numSubSamples; ++i) {
+ const uint32_t clearBytes =
+ mFDP->ConsumeIntegralInRange<uint32_t>(0, kMaxNumBytes);
+ const uint32_t encryptedBytes =
+ mFDP->ConsumeIntegralInRange<uint32_t>(0, kMaxNumBytes);
+ subSamples[i].numBytesOfClearData = clearBytes;
+ subSamples[i].numBytesOfEncryptedData = encryptedBytes;
+ totalSize += subSamples[i].numBytesOfClearData;
+ totalSize += subSamples[i].numBytesOfEncryptedData;
+ }
+
+ // The first totalSize bytes of shared memory is the encrypted
+ // input, the second totalSize bytes is the decrypted output.
+ size_t memoryBytes = totalSize * 2;
+
+ sp<IAllocator> ashmemAllocator = IAllocator::getService("ashmem");
+ if (!ashmemAllocator.get()) {
+ return;
+ }
+
+ hidl_memory hidlMemory;
+ ashmemAllocator->allocate(memoryBytes, [&]([[maybe_unused]] bool success,
+ const hidl_memory &memory) {
+ mCryptoPlugin->setSharedBufferBase(memory, kSegmentIndex);
+ hidlMemory = memory;
+ });
+
+ sp<IMemory> mappedMemory = mapMemory(hidlMemory);
+ if (!mappedMemory.get()) {
+ return;
+ }
+ mCryptoPlugin->setSharedBufferBase(hidlMemory, kSegmentIndex);
+
+ uint32_t srcBufferId =
+ mFDP->ConsumeBool() ? kSegmentIndex : mFDP->ConsumeIntegral<uint32_t>();
+ const SharedBuffer sourceBuffer = {
+ .bufferId = srcBufferId, .offset = 0, .size = totalSize};
+
+ BufferType type = mFDP->ConsumeBool() ? BufferType::SHARED_MEMORY
+ : BufferType::NATIVE_HANDLE;
+ uint32_t destBufferId =
+ mFDP->ConsumeBool() ? kSegmentIndex : mFDP->ConsumeIntegral<uint32_t>();
+ const DestinationBuffer destBuffer = {
+ .type = type,
+ {.bufferId = destBufferId, .offset = totalSize, .size = totalSize},
+ .secureMemory = nullptr};
+
+ const uint64_t offset = 0;
+ uint32_t bytesWritten = 0;
+ hidl_array<uint8_t, kAESBlockSize> keyId =
+ hidl_array<uint8_t, kAESBlockSize>(data);
+ hidl_array<uint8_t, kAESBlockSize> iv =
+ hidl_array<uint8_t, kAESBlockSize>(data);
+ Mode mode = getValueFromArray(mFDP, kCryptoMode);
+ mCryptoPlugin->decrypt(
+ mFDP->ConsumeBool(), keyId, iv, mode, pattern, subSamples, sourceBuffer,
+ offset, destBuffer,
+ [&]([[maybe_unused]] Status status, uint32_t count,
+ [[maybe_unused]] string detailedError) { bytesWritten = count; });
+ drm::V1_4::IDrmPlugin::getLogMessages_cb cb =
+ [&]([[maybe_unused]] drm::V1_4::Status status,
+ [[maybe_unused]] hidl_vec<drm::V1_4::LogMessage> logs) {};
+ mCryptoPluginV1_4->getLogMessages(cb);
+}
+
+bool ClearKeyFuzzer::invokeDrmFactory() {
+ hidl_string packageName(
+ mFDP->ConsumeRandomLengthString(kMaxStringLength).c_str());
+ hidl_string mimeType(getValueFromArray(mFDP, kMimeType));
+ SecurityLevel securityLevel =
+ mFDP->ConsumeBool()
+ ? getValueFromArray(mFDP, kSecurityLevel)
+ : static_cast<SecurityLevel>(mFDP->ConsumeIntegral<uint32_t>());
+ const hidl_array<uint8_t, 16> uuid =
+ mFDP->ConsumeBool() ? kClearKeyUUID : kInvalidUUID;
+ mDrmFactory->isCryptoSchemeSupported_1_2(uuid, mimeType, securityLevel);
+ mDrmFactory->createPlugin(
+ uuid, packageName, [&](Status status, const sp<IDrmPlugin> &plugin) {
+ if (status == Status::OK) {
+ mDrmPlugin = plugin.get();
+ mDrmPluginV1_1 = drm::V1_1::IDrmPlugin::castFrom(mDrmPlugin);
+ mDrmPluginV1_2 = drm::V1_2::IDrmPlugin::castFrom(mDrmPlugin);
+ mDrmPluginV1_4 = drm::V1_4::IDrmPlugin::castFrom(mDrmPlugin);
+ }
+ });
+
+ std::vector<hidl_array<uint8_t, 16>> supportedSchemes;
+ mDrmFactory->getSupportedCryptoSchemes(
+ [&](const hidl_vec<hidl_array<uint8_t, 16>> &schemes) {
+ for (const auto &scheme : schemes) {
+ supportedSchemes.push_back(scheme);
+ }
+ });
+
+ if (!(mDrmPlugin && mDrmPluginV1_1 && mDrmPluginV1_2 && mDrmPluginV1_4)) {
+ return false;
+ }
+ return true;
+}
+
+bool ClearKeyFuzzer::invokeCryptoFactory() {
+ const hidl_array<uint8_t, 16> uuid =
+ mFDP->ConsumeBool() ? kClearKeyUUID : kInvalidUUID;
+ mCryptoFactory->createPlugin(
+ uuid, mSessionId, [this](Status status, const sp<ICryptoPlugin> &plugin) {
+ if (status == Status::OK) {
+ mCryptoPlugin = plugin;
+ mCryptoPluginV1_4 = drm::V1_4::ICryptoPlugin::castFrom(mCryptoPlugin);
+ }
+ });
+
+ if (!mCryptoPlugin && !mCryptoPluginV1_4) {
+ return false;
+ }
+ return true;
+}
+
+void ClearKeyFuzzer::invokeDrm(const uint8_t *data, size_t size) {
+ if (!invokeDrmFactory()) {
+ return;
+ }
+ invokeDrmPlugin(data, size);
+}
+
+void ClearKeyFuzzer::invokeCrypto(const uint8_t *data) {
+ if (!invokeCryptoFactory()) {
+ return;
+ }
+ invokeCryptoPlugin(data);
+}
+
+void ClearKeyFuzzer::process(const uint8_t *data, size_t size) {
+ mFDP = new FuzzedDataProvider(data, size);
+ invokeDrm(data, size);
+ invokeCrypto(data);
+ delete mFDP;
+}
+
+bool ClearKeyFuzzer::init() {
+ mCryptoFactory =
+ android::hardware::drm::V1_4::clearkey::createCryptoFactory();
+ mDrmFactory = android::hardware::drm::V1_4::clearkey::createDrmFactory();
+ if (!mDrmFactory && !mCryptoFactory) {
+ return false;
+ }
+ return true;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ if (size < kAESBlockSize) {
+ return 0;
+ }
+ ClearKeyFuzzer clearKeyFuzzer;
+ if (clearKeyFuzzer.init()) {
+ clearKeyFuzzer.process(data, size);
+ }
+ return 0;
+}
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index bd6db55..a1e1702 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -55,6 +55,7 @@
// for audio_track_cblk_t::mState, to match TrackBase.h
static inline constexpr int CBLK_STATE_IDLE = 0;
+static inline constexpr int CBLK_STATE_ACTIVE = 6;
static inline constexpr int CBLK_STATE_PAUSING = 7;
/**
diff --git a/media/OWNERS b/media/OWNERS
index 099729f..4a25b68 100644
--- a/media/OWNERS
+++ b/media/OWNERS
@@ -1,7 +1,6 @@
# Bug component: 1344
elaurent@google.com
essick@google.com
-hkuang@google.com
hunga@google.com
jiabin@google.com
jmtrivi@google.com
diff --git a/media/TEST_MAPPING b/media/TEST_MAPPING
index 5bc7262..41fe080 100644
--- a/media/TEST_MAPPING
+++ b/media/TEST_MAPPING
@@ -3,18 +3,18 @@
"presubmit-large": [
// runs whenever we change something in this tree
{
- "name": "CtsMediaTestCases",
+ "name": "CtsMediaCodecTestCases",
"options": [
{
- "include-filter": "android.media.cts.EncodeDecodeTest"
+ "include-filter": "android.media.codec.cts.EncodeDecodeTest"
}
]
},
{
- "name": "CtsMediaTestCases",
+ "name": "CtsMediaCodecTestCases",
"options": [
{
- "include-filter": "android.media.cts.DecodeEditEncodeTest"
+ "include-filter": "android.media.codec.cts.DecodeEditEncodeTest"
}
]
}
@@ -46,18 +46,18 @@
// runs regularly, independent of changes in this tree.
// signals if changes elsewhere break media functionality
{
- "name": "CtsMediaTestCases",
+ "name": "CtsMediaCodecTestCases",
"options": [
{
- "include-filter": "android.media.cts.EncodeDecodeTest"
+ "include-filter": "android.media.codec.cts.EncodeDecodeTest"
}
]
},
{
- "name": "CtsMediaTestCases",
+ "name": "CtsMediaCodecTestCases",
"options": [
{
- "include-filter": "android.media.cts.DecodeEditEncodeTest"
+ "include-filter": "android.media.codec.cts.DecodeEditEncodeTest"
}
]
}
diff --git a/media/bufferpool/1.0/vts/OWNERS b/media/bufferpool/1.0/vts/OWNERS
index 6733e0c..db54d45 100644
--- a/media/bufferpool/1.0/vts/OWNERS
+++ b/media/bufferpool/1.0/vts/OWNERS
@@ -1,6 +1,5 @@
# Media team
lajos@google.com
-pawin@google.com
taklee@google.com
wonsik@google.com
diff --git a/media/bufferpool/2.0/tests/OWNERS b/media/bufferpool/2.0/tests/OWNERS
index 6733e0c..db54d45 100644
--- a/media/bufferpool/2.0/tests/OWNERS
+++ b/media/bufferpool/2.0/tests/OWNERS
@@ -1,6 +1,5 @@
# Media team
lajos@google.com
-pawin@google.com
taklee@google.com
wonsik@google.com
diff --git a/media/codec2/OWNERS b/media/codec2/OWNERS
index 46a9fca..7d40041 100644
--- a/media/codec2/OWNERS
+++ b/media/codec2/OWNERS
@@ -1,5 +1,4 @@
set noparent
wonsik@google.com
lajos@google.com
-pawin@google.com
taklee@google.com
diff --git a/media/codec2/TEST_MAPPING b/media/codec2/TEST_MAPPING
index 16cb323..f477f1c 100644
--- a/media/codec2/TEST_MAPPING
+++ b/media/codec2/TEST_MAPPING
@@ -35,6 +35,50 @@
"exclude-filter": "android.media.audio.cts.AudioRecordTest"
}
]
+ },
+ {
+ "name": "CtsMediaDecoderTestCases",
+ "options": [
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.RequiresDevice"
+ }
+ ]
+ },
+ {
+ "name": "CtsMediaEncoderTestCases",
+ "options": [
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.RequiresDevice"
+ }
+ ]
+ },
+ {
+ "name": "CtsMediaCodecTestCases",
+ "options": [
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.RequiresDevice"
+ }
+ ]
+ },
+ {
+ "name": "CtsMediaPlayerTestCases",
+ "options": [
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.RequiresDevice"
+ }
+ ]
}
]
}
diff --git a/media/codec2/components/aom/C2SoftAomDec.cpp b/media/codec2/components/aom/C2SoftAomDec.cpp
index c08cd59..c7985ca 100644
--- a/media/codec2/components/aom/C2SoftAomDec.cpp
+++ b/media/codec2/components/aom/C2SoftAomDec.cpp
@@ -505,124 +505,6 @@
}
}
-static void copyOutputBufferToYuvPlanarFrame(
- uint8_t *dstY, uint8_t *dstU, uint8_t *dstV,
- const uint8_t *srcY, const uint8_t *srcU, const uint8_t *srcV,
- size_t srcYStride, size_t srcUStride, size_t srcVStride,
- size_t dstYStride, size_t dstUVStride,
- uint32_t width, uint32_t height) {
-
- for (size_t i = 0; i < height; ++i) {
- memcpy(dstY, srcY, width);
- srcY += srcYStride;
- dstY += dstYStride;
- }
-
- for (size_t i = 0; i < height / 2; ++i) {
- memcpy(dstV, srcV, width / 2);
- srcV += srcVStride;
- dstV += dstUVStride;
- }
-
- for (size_t i = 0; i < height / 2; ++i) {
- memcpy(dstU, srcU, width / 2);
- srcU += srcUStride;
- dstU += dstUVStride;
- }
-}
-
-static void convertYUV420Planar16ToY410(uint32_t *dst,
- const uint16_t *srcY, const uint16_t *srcU, const uint16_t *srcV,
- size_t srcYStride, size_t srcUStride, size_t srcVStride,
- size_t dstStride, size_t width, size_t height) {
-
- // Converting two lines at a time, slightly faster
- for (size_t y = 0; y < height; y += 2) {
- uint32_t *dstTop = (uint32_t *) dst;
- uint32_t *dstBot = (uint32_t *) (dst + dstStride);
- uint16_t *ySrcTop = (uint16_t*) srcY;
- uint16_t *ySrcBot = (uint16_t*) (srcY + srcYStride);
- uint16_t *uSrc = (uint16_t*) srcU;
- uint16_t *vSrc = (uint16_t*) srcV;
-
- uint32_t u01, v01, y01, y23, y45, y67, uv0, uv1;
- size_t x = 0;
- for (; x < width - 3; x += 4) {
-
- u01 = *((uint32_t*)uSrc); uSrc += 2;
- v01 = *((uint32_t*)vSrc); vSrc += 2;
-
- y01 = *((uint32_t*)ySrcTop); ySrcTop += 2;
- y23 = *((uint32_t*)ySrcTop); ySrcTop += 2;
- y45 = *((uint32_t*)ySrcBot); ySrcBot += 2;
- y67 = *((uint32_t*)ySrcBot); ySrcBot += 2;
-
- uv0 = (u01 & 0x3FF) | ((v01 & 0x3FF) << 20);
- uv1 = (u01 >> 16) | ((v01 >> 16) << 20);
-
- *dstTop++ = 3 << 30 | ((y01 & 0x3FF) << 10) | uv0;
- *dstTop++ = 3 << 30 | ((y01 >> 16) << 10) | uv0;
- *dstTop++ = 3 << 30 | ((y23 & 0x3FF) << 10) | uv1;
- *dstTop++ = 3 << 30 | ((y23 >> 16) << 10) | uv1;
-
- *dstBot++ = 3 << 30 | ((y45 & 0x3FF) << 10) | uv0;
- *dstBot++ = 3 << 30 | ((y45 >> 16) << 10) | uv0;
- *dstBot++ = 3 << 30 | ((y67 & 0x3FF) << 10) | uv1;
- *dstBot++ = 3 << 30 | ((y67 >> 16) << 10) | uv1;
- }
-
- // There should be at most 2 more pixels to process. Note that we don't
- // need to consider odd case as the buffer is always aligned to even.
- if (x < width) {
- u01 = *uSrc;
- v01 = *vSrc;
- y01 = *((uint32_t*)ySrcTop);
- y45 = *((uint32_t*)ySrcBot);
- uv0 = (u01 & 0x3FF) | ((v01 & 0x3FF) << 20);
- *dstTop++ = ((y01 & 0x3FF) << 10) | uv0;
- *dstTop++ = ((y01 >> 16) << 10) | uv0;
- *dstBot++ = ((y45 & 0x3FF) << 10) | uv0;
- *dstBot++ = ((y45 >> 16) << 10) | uv0;
- }
-
- srcY += srcYStride * 2;
- srcU += srcUStride;
- srcV += srcVStride;
- dst += dstStride * 2;
- }
-
- return;
-}
-
-static void convertYUV420Planar16ToYUV420Planar(
- uint8_t *dstY, uint8_t *dstU, uint8_t *dstV,
- const uint16_t *srcY, const uint16_t *srcU, const uint16_t *srcV,
- size_t srcYStride, size_t srcUStride, size_t srcVStride,
- size_t dstYStride, size_t dstUVStride,
- size_t width, size_t height) {
-
- for (size_t y = 0; y < height; ++y) {
- for (size_t x = 0; x < width; ++x) {
- dstY[x] = (uint8_t)(srcY[x] >> 2);
- }
-
- srcY += srcYStride;
- dstY += dstYStride;
- }
-
- for (size_t y = 0; y < (height + 1) / 2; ++y) {
- for (size_t x = 0; x < (width + 1) / 2; ++x) {
- dstU[x] = (uint8_t)(srcU[x] >> 2);
- dstV[x] = (uint8_t)(srcV[x] >> 2);
- }
-
- srcU += srcUStride;
- srcV += srcVStride;
- dstU += dstUVStride;
- dstV += dstUVStride;
- }
- return;
-}
bool C2SoftAomDec::outputBuffer(
const std::shared_ptr<C2BlockPool> &pool,
const std::unique_ptr<C2Work> &work)
@@ -711,21 +593,16 @@
dstYStride / sizeof(uint32_t),
mWidth, mHeight);
} else {
- convertYUV420Planar16ToYUV420Planar(dstY, dstU, dstV,
- srcY, srcU, srcV,
- srcYStride / 2, srcUStride / 2, srcVStride / 2,
- dstYStride, dstUVStride,
- mWidth, mHeight);
+ convertYUV420Planar16ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride / 2,
+ srcUStride / 2, srcVStride / 2, dstYStride, dstUVStride,
+ mWidth, mHeight);
}
} else {
const uint8_t *srcY = (const uint8_t *)img->planes[AOM_PLANE_Y];
const uint8_t *srcU = (const uint8_t *)img->planes[AOM_PLANE_U];
const uint8_t *srcV = (const uint8_t *)img->planes[AOM_PLANE_V];
- copyOutputBufferToYuvPlanarFrame(
- dstY, dstU, dstV, srcY, srcU, srcV,
- srcYStride, srcUStride, srcVStride,
- dstYStride, dstUVStride,
- mWidth, mHeight);
+ convertYUV420Planar8ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride, srcUStride,
+ srcVStride, dstYStride, dstUVStride, mWidth, mHeight);
}
finishWork(*(int64_t*)img->user_priv, work, std::move(block));
block = nullptr;
diff --git a/media/codec2/components/base/SimpleC2Component.cpp b/media/codec2/components/base/SimpleC2Component.cpp
index 6c4b7d9..99ff450 100644
--- a/media/codec2/components/base/SimpleC2Component.cpp
+++ b/media/codec2/components/base/SimpleC2Component.cpp
@@ -29,7 +29,179 @@
#include <SimpleC2Component.h>
namespace android {
+constexpr uint8_t kNeutralUVBitDepth8 = 128;
+constexpr uint16_t kNeutralUVBitDepth10 = 512;
+void convertYUV420Planar8ToYV12(uint8_t *dstY, uint8_t *dstU, uint8_t *dstV, const uint8_t *srcY,
+ const uint8_t *srcU, const uint8_t *srcV, size_t srcYStride,
+ size_t srcUStride, size_t srcVStride, size_t dstYStride,
+ size_t dstUVStride, uint32_t width, uint32_t height,
+ bool isMonochrome) {
+ for (size_t i = 0; i < height; ++i) {
+ memcpy(dstY, srcY, width);
+ srcY += srcYStride;
+ dstY += dstYStride;
+ }
+
+ if (isMonochrome) {
+ // Fill with neutral U/V values.
+ for (size_t i = 0; i < height / 2; ++i) {
+ memset(dstV, kNeutralUVBitDepth8, width / 2);
+ memset(dstU, kNeutralUVBitDepth8, width / 2);
+ dstV += dstUVStride;
+ dstU += dstUVStride;
+ }
+ return;
+ }
+
+ for (size_t i = 0; i < height / 2; ++i) {
+ memcpy(dstV, srcV, width / 2);
+ srcV += srcVStride;
+ dstV += dstUVStride;
+ }
+
+ for (size_t i = 0; i < height / 2; ++i) {
+ memcpy(dstU, srcU, width / 2);
+ srcU += srcUStride;
+ dstU += dstUVStride;
+ }
+}
+
+void convertYUV420Planar16ToY410(uint32_t *dst, const uint16_t *srcY, const uint16_t *srcU,
+ const uint16_t *srcV, size_t srcYStride, size_t srcUStride,
+ size_t srcVStride, size_t dstStride, size_t width, size_t height) {
+ // Converting two lines at a time, slightly faster
+ for (size_t y = 0; y < height; y += 2) {
+ uint32_t *dstTop = (uint32_t *)dst;
+ uint32_t *dstBot = (uint32_t *)(dst + dstStride);
+ uint16_t *ySrcTop = (uint16_t *)srcY;
+ uint16_t *ySrcBot = (uint16_t *)(srcY + srcYStride);
+ uint16_t *uSrc = (uint16_t *)srcU;
+ uint16_t *vSrc = (uint16_t *)srcV;
+
+ uint32_t u01, v01, y01, y23, y45, y67, uv0, uv1;
+ size_t x = 0;
+ for (; x < width - 3; x += 4) {
+ u01 = *((uint32_t *)uSrc);
+ uSrc += 2;
+ v01 = *((uint32_t *)vSrc);
+ vSrc += 2;
+
+ y01 = *((uint32_t *)ySrcTop);
+ ySrcTop += 2;
+ y23 = *((uint32_t *)ySrcTop);
+ ySrcTop += 2;
+ y45 = *((uint32_t *)ySrcBot);
+ ySrcBot += 2;
+ y67 = *((uint32_t *)ySrcBot);
+ ySrcBot += 2;
+
+ uv0 = (u01 & 0x3FF) | ((v01 & 0x3FF) << 20);
+ uv1 = (u01 >> 16) | ((v01 >> 16) << 20);
+
+ *dstTop++ = 3 << 30 | ((y01 & 0x3FF) << 10) | uv0;
+ *dstTop++ = 3 << 30 | ((y01 >> 16) << 10) | uv0;
+ *dstTop++ = 3 << 30 | ((y23 & 0x3FF) << 10) | uv1;
+ *dstTop++ = 3 << 30 | ((y23 >> 16) << 10) | uv1;
+
+ *dstBot++ = 3 << 30 | ((y45 & 0x3FF) << 10) | uv0;
+ *dstBot++ = 3 << 30 | ((y45 >> 16) << 10) | uv0;
+ *dstBot++ = 3 << 30 | ((y67 & 0x3FF) << 10) | uv1;
+ *dstBot++ = 3 << 30 | ((y67 >> 16) << 10) | uv1;
+ }
+
+ // There should be at most 2 more pixels to process. Note that we don't
+ // need to consider odd case as the buffer is always aligned to even.
+ if (x < width) {
+ u01 = *uSrc;
+ v01 = *vSrc;
+ y01 = *((uint32_t *)ySrcTop);
+ y45 = *((uint32_t *)ySrcBot);
+ uv0 = (u01 & 0x3FF) | ((v01 & 0x3FF) << 20);
+ *dstTop++ = ((y01 & 0x3FF) << 10) | uv0;
+ *dstTop++ = ((y01 >> 16) << 10) | uv0;
+ *dstBot++ = ((y45 & 0x3FF) << 10) | uv0;
+ *dstBot++ = ((y45 >> 16) << 10) | uv0;
+ }
+
+ srcY += srcYStride * 2;
+ srcU += srcUStride;
+ srcV += srcVStride;
+ dst += dstStride * 2;
+ }
+}
+
+void convertYUV420Planar16ToYV12(uint8_t *dstY, uint8_t *dstU, uint8_t *dstV, const uint16_t *srcY,
+ const uint16_t *srcU, const uint16_t *srcV, size_t srcYStride,
+ size_t srcUStride, size_t srcVStride, size_t dstYStride,
+ size_t dstUVStride, size_t width, size_t height,
+ bool isMonochrome) {
+ for (size_t y = 0; y < height; ++y) {
+ for (size_t x = 0; x < width; ++x) {
+ dstY[x] = (uint8_t)(srcY[x] >> 2);
+ }
+ srcY += srcYStride;
+ dstY += dstYStride;
+ }
+
+ if (isMonochrome) {
+ // Fill with neutral U/V values.
+ for (size_t y = 0; y < (height + 1) / 2; ++y) {
+ memset(dstV, kNeutralUVBitDepth8, (width + 1) / 2);
+ memset(dstU, kNeutralUVBitDepth8, (width + 1) / 2);
+ dstV += dstUVStride;
+ dstU += dstUVStride;
+ }
+ return;
+ }
+
+ for (size_t y = 0; y < (height + 1) / 2; ++y) {
+ for (size_t x = 0; x < (width + 1) / 2; ++x) {
+ dstU[x] = (uint8_t)(srcU[x] >> 2);
+ dstV[x] = (uint8_t)(srcV[x] >> 2);
+ }
+ srcU += srcUStride;
+ srcV += srcVStride;
+ dstU += dstUVStride;
+ dstV += dstUVStride;
+ }
+}
+
+void convertYUV420Planar16ToP010(uint16_t *dstY, uint16_t *dstUV, const uint16_t *srcY,
+ const uint16_t *srcU, const uint16_t *srcV, size_t srcYStride,
+ size_t srcUStride, size_t srcVStride, size_t dstYStride,
+ size_t dstUVStride, size_t width, size_t height,
+ bool isMonochrome) {
+ for (size_t y = 0; y < height; ++y) {
+ for (size_t x = 0; x < width; ++x) {
+ dstY[x] = srcY[x] << 6;
+ }
+ srcY += srcYStride;
+ dstY += dstYStride;
+ }
+
+ if (isMonochrome) {
+ // Fill with neutral U/V values.
+ for (size_t y = 0; y < (height + 1) / 2; ++y) {
+ for (size_t x = 0; x < (width + 1) / 2; ++x) {
+ dstUV[2 * x] = kNeutralUVBitDepth10 << 6;
+ dstUV[2 * x + 1] = kNeutralUVBitDepth10 << 6;
+ }
+ dstUV += dstUVStride;
+ }
+ return;
+ }
+
+ for (size_t y = 0; y < (height + 1) / 2; ++y) {
+ for (size_t x = 0; x < (width + 1) / 2; ++x) {
+ dstUV[2 * x] = srcU[x] << 6;
+ dstUV[2 * x + 1] = srcV[x] << 6;
+ }
+ srcU += srcUStride;
+ srcV += srcVStride;
+ dstUV += dstUVStride;
+ }
+}
std::unique_ptr<C2Work> SimpleC2Component::WorkQueue::pop_front() {
std::unique_ptr<C2Work> work = std::move(mQueue.front().work);
mQueue.pop_front();
diff --git a/media/codec2/components/base/include/SimpleC2Component.h b/media/codec2/components/base/include/SimpleC2Component.h
index e5e16d8..3b4e212 100644
--- a/media/codec2/components/base/include/SimpleC2Component.h
+++ b/media/codec2/components/base/include/SimpleC2Component.h
@@ -28,6 +28,24 @@
namespace android {
+void convertYUV420Planar8ToYV12(uint8_t *dstY, uint8_t *dstU, uint8_t *dstV, const uint8_t *srcY,
+ const uint8_t *srcU, const uint8_t *srcV, size_t srcYStride,
+ size_t srcUStride, size_t srcVStride, size_t dstYStride,
+ size_t dstUVStride, uint32_t width, uint32_t height,
+ bool isMonochrome = false);
+void convertYUV420Planar16ToY410(uint32_t *dst, const uint16_t *srcY, const uint16_t *srcU,
+ const uint16_t *srcV, size_t srcYStride, size_t srcUStride,
+ size_t srcVStride, size_t dstStride, size_t width, size_t height);
+void convertYUV420Planar16ToYV12(uint8_t *dstY, uint8_t *dstU, uint8_t *dstV, const uint16_t *srcY,
+ const uint16_t *srcU, const uint16_t *srcV, size_t srcYStride,
+ size_t srcUStride, size_t srcVStride, size_t dstYStride,
+ size_t dstUVStride, size_t width, size_t height,
+ bool isMonochrome = false);
+void convertYUV420Planar16ToP010(uint16_t *dstY, uint16_t *dstUV, const uint16_t *srcY,
+ const uint16_t *srcU, const uint16_t *srcV, size_t srcYStride,
+ size_t srcUStride, size_t srcVStride, size_t dstYStride,
+ size_t dstUVStride, size_t width, size_t height,
+ bool isMonochrome = false);
class SimpleC2Component
: public C2Component, public std::enable_shared_from_this<SimpleC2Component> {
public:
diff --git a/media/codec2/components/gav1/C2SoftGav1Dec.cpp b/media/codec2/components/gav1/C2SoftGav1Dec.cpp
index 7bd3358..ffe72dc 100644
--- a/media/codec2/components/gav1/C2SoftGav1Dec.cpp
+++ b/media/codec2/components/gav1/C2SoftGav1Dec.cpp
@@ -20,6 +20,7 @@
#include <C2Debug.h>
#include <C2PlatformSupport.h>
+#include <Codec2BufferUtils.h>
#include <Codec2Mapper.h>
#include <SimpleC2Interface.h>
#include <log/log.h>
@@ -27,15 +28,12 @@
#include <media/stagefright/foundation/MediaDefs.h>
namespace android {
-namespace {
-
-constexpr uint8_t NEUTRAL_UV_VALUE = 128;
-
-} // namespace
// codecname set and passed in as a compile flag from Android.bp
constexpr char COMPONENT_NAME[] = CODECNAME;
+constexpr size_t kMinInputBufferSize = 2 * 1024 * 1024;
+
class C2SoftGav1Dec::IntfImpl : public SimpleInterface<void>::BaseParams {
public:
explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper)
@@ -114,8 +112,7 @@
.build());
addParameter(DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
- .withDefault(new C2StreamMaxBufferSizeInfo::input(
- 0u, 320 * 240 * 3 / 4))
+ .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, kMinInputBufferSize))
.withFields({
C2F(mMaxInputSize, value).any(),
})
@@ -231,9 +228,9 @@
bool mayBlock, C2P<C2StreamMaxBufferSizeInfo::input> &me,
const C2P<C2StreamMaxPictureSizeTuning::output> &maxSize) {
(void)mayBlock;
- // assume compression ratio of 2
- me.set().value =
- (((maxSize.v.width + 63) / 64) * ((maxSize.v.height + 63) / 64) * 3072);
+ // assume compression ratio of 2, but enforce a floor
+ me.set().value = c2_max((((maxSize.v.width + 63) / 64)
+ * ((maxSize.v.height + 63) / 64) * 3072), kMinInputBufferSize);
return C2R::Ok();
}
@@ -338,6 +335,7 @@
std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
mIntf(intfImpl),
mCodecCtx(nullptr) {
+ mIsFormatR10G10B10A2Supported = IsFormatR10G10B10A2SupportedForLegacyRendering();
gettimeofday(&mTimeStart, nullptr);
gettimeofday(&mTimeEnd, nullptr);
}
@@ -543,150 +541,6 @@
}
}
-static void copyOutputBufferToYV12Frame(uint8_t *dstY, uint8_t *dstU, uint8_t *dstV,
- const uint8_t *srcY, const uint8_t *srcU, const uint8_t *srcV,
- size_t srcYStride, size_t srcUStride, size_t srcVStride,
- size_t dstYStride, size_t dstUVStride,
- uint32_t width, uint32_t height,
- bool isMonochrome) {
-
- for (size_t i = 0; i < height; ++i) {
- memcpy(dstY, srcY, width);
- srcY += srcYStride;
- dstY += dstYStride;
- }
-
- if (isMonochrome) {
- // Fill with neutral U/V values.
- for (size_t i = 0; i < height / 2; ++i) {
- memset(dstV, NEUTRAL_UV_VALUE, width / 2);
- memset(dstU, NEUTRAL_UV_VALUE, width / 2);
- dstV += dstUVStride;
- dstU += dstUVStride;
- }
- return;
- }
-
- for (size_t i = 0; i < height / 2; ++i) {
- memcpy(dstV, srcV, width / 2);
- srcV += srcVStride;
- dstV += dstUVStride;
- }
-
- for (size_t i = 0; i < height / 2; ++i) {
- memcpy(dstU, srcU, width / 2);
- srcU += srcUStride;
- dstU += dstUVStride;
- }
-}
-
-static void convertYUV420Planar16ToY410(uint32_t *dst, const uint16_t *srcY,
- const uint16_t *srcU,
- const uint16_t *srcV, size_t srcYStride,
- size_t srcUStride, size_t srcVStride,
- size_t dstStride, size_t width,
- size_t height) {
- // Converting two lines at a time, slightly faster
- for (size_t y = 0; y < height; y += 2) {
- uint32_t *dstTop = (uint32_t *)dst;
- uint32_t *dstBot = (uint32_t *)(dst + dstStride);
- uint16_t *ySrcTop = (uint16_t *)srcY;
- uint16_t *ySrcBot = (uint16_t *)(srcY + srcYStride);
- uint16_t *uSrc = (uint16_t *)srcU;
- uint16_t *vSrc = (uint16_t *)srcV;
-
- uint32_t u01, v01, y01, y23, y45, y67, uv0, uv1;
- size_t x = 0;
- for (; x < width - 3; x += 4) {
- u01 = *((uint32_t *)uSrc);
- uSrc += 2;
- v01 = *((uint32_t *)vSrc);
- vSrc += 2;
-
- y01 = *((uint32_t *)ySrcTop);
- ySrcTop += 2;
- y23 = *((uint32_t *)ySrcTop);
- ySrcTop += 2;
- y45 = *((uint32_t *)ySrcBot);
- ySrcBot += 2;
- y67 = *((uint32_t *)ySrcBot);
- ySrcBot += 2;
-
- uv0 = (u01 & 0x3FF) | ((v01 & 0x3FF) << 20);
- uv1 = (u01 >> 16) | ((v01 >> 16) << 20);
-
- *dstTop++ = 3 << 30 | ((y01 & 0x3FF) << 10) | uv0;
- *dstTop++ = 3 << 30 | ((y01 >> 16) << 10) | uv0;
- *dstTop++ = 3 << 30 | ((y23 & 0x3FF) << 10) | uv1;
- *dstTop++ = 3 << 30 | ((y23 >> 16) << 10) | uv1;
-
- *dstBot++ = 3 << 30 | ((y45 & 0x3FF) << 10) | uv0;
- *dstBot++ = 3 << 30 | ((y45 >> 16) << 10) | uv0;
- *dstBot++ = 3 << 30 | ((y67 & 0x3FF) << 10) | uv1;
- *dstBot++ = 3 << 30 | ((y67 >> 16) << 10) | uv1;
- }
-
- // There should be at most 2 more pixels to process. Note that we don't
- // need to consider odd case as the buffer is always aligned to even.
- if (x < width) {
- u01 = *uSrc;
- v01 = *vSrc;
- y01 = *((uint32_t *)ySrcTop);
- y45 = *((uint32_t *)ySrcBot);
- uv0 = (u01 & 0x3FF) | ((v01 & 0x3FF) << 20);
- *dstTop++ = ((y01 & 0x3FF) << 10) | uv0;
- *dstTop++ = ((y01 >> 16) << 10) | uv0;
- *dstBot++ = ((y45 & 0x3FF) << 10) | uv0;
- *dstBot++ = ((y45 >> 16) << 10) | uv0;
- }
-
- srcY += srcYStride * 2;
- srcU += srcUStride;
- srcV += srcVStride;
- dst += dstStride * 2;
- }
-}
-
-static void convertYUV420Planar16ToYUV420Planar(
- uint8_t *dstY, uint8_t *dstU, uint8_t *dstV,
- const uint16_t *srcY, const uint16_t *srcU, const uint16_t *srcV,
- size_t srcYStride, size_t srcUStride, size_t srcVStride,
- size_t dstYStride, size_t dstUVStride,
- size_t width, size_t height, bool isMonochrome) {
-
- for (size_t y = 0; y < height; ++y) {
- for (size_t x = 0; x < width; ++x) {
- dstY[x] = (uint8_t)(srcY[x] >> 2);
- }
-
- srcY += srcYStride;
- dstY += dstYStride;
- }
-
- if (isMonochrome) {
- // Fill with neutral U/V values.
- for (size_t y = 0; y < (height + 1) / 2; ++y) {
- memset(dstV, NEUTRAL_UV_VALUE, (width + 1) / 2);
- memset(dstU, NEUTRAL_UV_VALUE, (width + 1) / 2);
- dstV += dstUVStride;
- dstU += dstUVStride;
- }
- return;
- }
-
- for (size_t y = 0; y < (height + 1) / 2; ++y) {
- for (size_t x = 0; x < (width + 1) / 2; ++x) {
- dstU[x] = (uint8_t)(srcU[x] >> 2);
- dstV[x] = (uint8_t)(srcV[x] >> 2);
- }
-
- srcU += srcUStride;
- srcV += srcVStride;
- dstU += dstUVStride;
- dstV += dstUVStride;
- }
-}
-
void C2SoftGav1Dec::getVuiParams(const libgav1::DecoderBuffer *buffer) {
VuiColorAspects vuiColorAspects;
vuiColorAspects.primaries = buffer->color_primary;
@@ -790,7 +644,14 @@
work->workletsProcessed = 1u;
return false;
}
- format = HAL_PIXEL_FORMAT_RGBA_1010102;
+ // TODO (b/201787956) For devices that do not support HAL_PIXEL_FORMAT_RGBA_1010102,
+ // HAL_PIXEL_FORMAT_YV12 is used as a temporary work around.
+ if (!mIsFormatR10G10B10A2Supported) {
+ ALOGE("HAL_PIXEL_FORMAT_RGBA_1010102 isn't supported");
+ format = HAL_PIXEL_FORMAT_YV12;
+ } else {
+ format = HAL_PIXEL_FORMAT_RGBA_1010102;
+ }
}
}
C2MemoryUsage usage = {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
@@ -832,22 +693,24 @@
const uint16_t *srcV = (const uint16_t *)buffer->plane[2];
if (format == HAL_PIXEL_FORMAT_RGBA_1010102) {
- convertYUV420Planar16ToY410(
- (uint32_t *)dstY, srcY, srcU, srcV, srcYStride / 2, srcUStride / 2,
- srcVStride / 2, dstYStride / sizeof(uint32_t), mWidth, mHeight);
+ convertYUV420Planar16ToY410((uint32_t *)dstY, srcY, srcU, srcV, srcYStride / 2,
+ srcUStride / 2, srcVStride / 2, dstYStride / sizeof(uint32_t),
+ mWidth, mHeight);
+ } else if (format == HAL_PIXEL_FORMAT_YCBCR_P010) {
+ convertYUV420Planar16ToP010((uint16_t *)dstY, (uint16_t *)dstU, srcY, srcU, srcV,
+ srcYStride / 2, srcUStride / 2, srcVStride / 2, dstYStride / 2,
+ dstUVStride / 2, mWidth, mHeight, isMonochrome);
} else {
- convertYUV420Planar16ToYUV420Planar(
- dstY, dstU, dstV, srcY, srcU, srcV, srcYStride / 2, srcUStride / 2,
- srcVStride / 2, dstYStride, dstUVStride, mWidth, mHeight,
- isMonochrome);
+ convertYUV420Planar16ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride / 2,
+ srcUStride / 2, srcVStride / 2, dstYStride, dstUVStride, mWidth,
+ mHeight, isMonochrome);
}
} else {
const uint8_t *srcY = (const uint8_t *)buffer->plane[0];
const uint8_t *srcU = (const uint8_t *)buffer->plane[1];
const uint8_t *srcV = (const uint8_t *)buffer->plane[2];
- copyOutputBufferToYV12Frame(
- dstY, dstU, dstV, srcY, srcU, srcV, srcYStride, srcUStride, srcVStride,
- dstYStride, dstUVStride, mWidth, mHeight, isMonochrome);
+ convertYUV420Planar8ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride, srcUStride,
+ srcVStride, dstYStride, dstUVStride, mWidth, mHeight, isMonochrome);
}
finishWork(buffer->user_private_data, work, std::move(block));
block = nullptr;
diff --git a/media/codec2/components/gav1/C2SoftGav1Dec.h b/media/codec2/components/gav1/C2SoftGav1Dec.h
index 134fa0d..f82992d 100644
--- a/media/codec2/components/gav1/C2SoftGav1Dec.h
+++ b/media/codec2/components/gav1/C2SoftGav1Dec.h
@@ -82,6 +82,7 @@
struct timeval mTimeStart; // Time at the start of decode()
struct timeval mTimeEnd; // Time at the end of decode()
+ bool mIsFormatR10G10B10A2Supported;
bool initDecoder();
void getVuiParams(const libgav1::DecoderBuffer *buffer);
diff --git a/media/codec2/components/hevc/C2SoftHevcDec.cpp b/media/codec2/components/hevc/C2SoftHevcDec.cpp
index 5f5b2ef..2a6adca 100644
--- a/media/codec2/components/hevc/C2SoftHevcDec.cpp
+++ b/media/codec2/components/hevc/C2SoftHevcDec.cpp
@@ -34,6 +34,7 @@
constexpr char COMPONENT_NAME[] = "c2.android.hevc.decoder";
constexpr uint32_t kDefaultOutputDelay = 8;
constexpr uint32_t kMaxOutputDelay = 16;
+constexpr size_t kMinInputBufferSize = 2 * 1024 * 1024;
} // namespace
class C2SoftHevcDec::IntfImpl : public SimpleInterface<void>::BaseParams {
@@ -108,7 +109,7 @@
addParameter(
DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
- .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, 320 * 240 * 3 / 4))
+ .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, kMinInputBufferSize))
.withFields({
C2F(mMaxInputSize, value).any(),
})
@@ -220,8 +221,9 @@
static C2R MaxInputSizeSetter(bool mayBlock, C2P<C2StreamMaxBufferSizeInfo::input> &me,
const C2P<C2StreamMaxPictureSizeTuning::output> &maxSize) {
(void)mayBlock;
- // assume compression ratio of 2
- me.set().value = (((maxSize.v.width + 63) / 64) * ((maxSize.v.height + 63) / 64) * 3072);
+ // assume compression ratio of 2, but enforce a floor
+ me.set().value = c2_max((((maxSize.v.width + 63) / 64)
+ * ((maxSize.v.height + 63) / 64) * 3072), kMinInputBufferSize);
return C2R::Ok();
}
diff --git a/media/codec2/components/mpeg4_h263/C2SoftMpeg4Dec.cpp b/media/codec2/components/mpeg4_h263/C2SoftMpeg4Dec.cpp
index 81f4679..54a1d0e 100644
--- a/media/codec2/components/mpeg4_h263/C2SoftMpeg4Dec.cpp
+++ b/media/codec2/components/mpeg4_h263/C2SoftMpeg4Dec.cpp
@@ -419,40 +419,6 @@
return resChanged;
}
-/* TODO: can remove temporary copy after library supports writing to display
- * buffer Y, U and V plane pointers using stride info. */
-static void copyOutputBufferToYuvPlanarFrame(
- uint8_t *dstY, uint8_t *dstU, uint8_t *dstV, uint8_t *src,
- size_t dstYStride, size_t dstUVStride,
- size_t srcYStride, uint32_t width,
- uint32_t height) {
- size_t srcUVStride = srcYStride / 2;
- uint8_t *srcStart = src;
-
- size_t vStride = align(height, 16);
- for (size_t i = 0; i < height; ++i) {
- memcpy(dstY, src, width);
- src += srcYStride;
- dstY += dstYStride;
- }
-
- /* U buffer */
- src = srcStart + vStride * srcYStride;
- for (size_t i = 0; i < height / 2; ++i) {
- memcpy(dstU, src, width / 2);
- src += srcUVStride;
- dstU += dstUVStride;
- }
-
- /* V buffer */
- src = srcStart + vStride * srcYStride * 5 / 4;
- for (size_t i = 0; i < height / 2; ++i) {
- memcpy(dstV, src, width / 2);
- src += srcUVStride;
- dstV += dstUVStride;
- }
-}
-
void C2SoftMpeg4Dec::process(
const std::unique_ptr<C2Work> &work,
const std::shared_ptr<C2BlockPool> &pool) {
@@ -636,11 +602,17 @@
C2PlanarLayout layout = wView.layout();
size_t dstYStride = layout.planes[C2PlanarLayout::PLANE_Y].rowInc;
size_t dstUVStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc;
- (void)copyOutputBufferToYuvPlanarFrame(
- outputBufferY, outputBufferU, outputBufferV,
- mOutputBuffer[mNumSamplesOutput & 1],
- dstYStride, dstUVStride,
- align(mWidth, 16), mWidth, mHeight);
+ size_t srcYStride = align(mWidth, 16);
+ size_t srcUStride = srcYStride / 2;
+ size_t srcVStride = srcYStride / 2;
+ size_t vStride = align(mHeight, 16);
+ const uint8_t *srcY = (const uint8_t *)mOutputBuffer[mNumSamplesOutput & 1];
+ const uint8_t *srcU = (const uint8_t *)srcY + vStride * srcYStride;
+ const uint8_t *srcV = (const uint8_t *)srcY + vStride * srcYStride * 5 / 4;
+
+ convertYUV420Planar8ToYV12(outputBufferY, outputBufferU, outputBufferV, srcY, srcU, srcV,
+ srcYStride, srcUStride, srcVStride, dstYStride, dstUVStride,
+ mWidth, mHeight);
inPos += inSize - (size_t)tmpInSize;
finishWork(workIndex, work);
diff --git a/media/codec2/components/vpx/C2SoftVpxDec.cpp b/media/codec2/components/vpx/C2SoftVpxDec.cpp
index 45e2ca8..0a27821 100644
--- a/media/codec2/components/vpx/C2SoftVpxDec.cpp
+++ b/media/codec2/components/vpx/C2SoftVpxDec.cpp
@@ -25,6 +25,7 @@
#include <C2Debug.h>
#include <C2PlatformSupport.h>
+#include <Codec2BufferUtils.h>
#include <SimpleC2Interface.h>
#include "C2SoftVpxDec.h"
@@ -351,6 +352,7 @@
mCodecCtx(nullptr),
mCoreCount(1),
mQueue(new Mutexed<ConversionQueue>) {
+ mIsFormatR10G10B10A2Supported = IsFormatR10G10B10A2SupportedForLegacyRendering();
}
C2SoftVpxDec::~C2SoftVpxDec() {
@@ -638,125 +640,6 @@
}
}
-static void copyOutputBufferToYuvPlanarFrame(
- uint8_t *dstY, uint8_t *dstU, uint8_t *dstV,
- const uint8_t *srcY, const uint8_t *srcU, const uint8_t *srcV,
- size_t srcYStride, size_t srcUStride, size_t srcVStride,
- size_t dstYStride, size_t dstUVStride,
- uint32_t width, uint32_t height) {
-
- for (size_t i = 0; i < height; ++i) {
- memcpy(dstY, srcY, width);
- srcY += srcYStride;
- dstY += dstYStride;
- }
-
- for (size_t i = 0; i < height / 2; ++i) {
- memcpy(dstV, srcV, width / 2);
- srcV += srcVStride;
- dstV += dstUVStride;
- }
-
- for (size_t i = 0; i < height / 2; ++i) {
- memcpy(dstU, srcU, width / 2);
- srcU += srcUStride;
- dstU += dstUVStride;
- }
-
-}
-
-static void convertYUV420Planar16ToY410(uint32_t *dst,
- const uint16_t *srcY, const uint16_t *srcU, const uint16_t *srcV,
- size_t srcYStride, size_t srcUStride, size_t srcVStride,
- size_t dstStride, size_t width, size_t height) {
-
- // Converting two lines at a time, slightly faster
- for (size_t y = 0; y < height; y += 2) {
- uint32_t *dstTop = (uint32_t *) dst;
- uint32_t *dstBot = (uint32_t *) (dst + dstStride);
- uint16_t *ySrcTop = (uint16_t*) srcY;
- uint16_t *ySrcBot = (uint16_t*) (srcY + srcYStride);
- uint16_t *uSrc = (uint16_t*) srcU;
- uint16_t *vSrc = (uint16_t*) srcV;
-
- uint32_t u01, v01, y01, y23, y45, y67, uv0, uv1;
- size_t x = 0;
- for (; x < width - 3; x += 4) {
-
- u01 = *((uint32_t*)uSrc); uSrc += 2;
- v01 = *((uint32_t*)vSrc); vSrc += 2;
-
- y01 = *((uint32_t*)ySrcTop); ySrcTop += 2;
- y23 = *((uint32_t*)ySrcTop); ySrcTop += 2;
- y45 = *((uint32_t*)ySrcBot); ySrcBot += 2;
- y67 = *((uint32_t*)ySrcBot); ySrcBot += 2;
-
- uv0 = (u01 & 0x3FF) | ((v01 & 0x3FF) << 20);
- uv1 = (u01 >> 16) | ((v01 >> 16) << 20);
-
- *dstTop++ = 3 << 30 | ((y01 & 0x3FF) << 10) | uv0;
- *dstTop++ = 3 << 30 | ((y01 >> 16) << 10) | uv0;
- *dstTop++ = 3 << 30 | ((y23 & 0x3FF) << 10) | uv1;
- *dstTop++ = 3 << 30 | ((y23 >> 16) << 10) | uv1;
-
- *dstBot++ = 3 << 30 | ((y45 & 0x3FF) << 10) | uv0;
- *dstBot++ = 3 << 30 | ((y45 >> 16) << 10) | uv0;
- *dstBot++ = 3 << 30 | ((y67 & 0x3FF) << 10) | uv1;
- *dstBot++ = 3 << 30 | ((y67 >> 16) << 10) | uv1;
- }
-
- // There should be at most 2 more pixels to process. Note that we don't
- // need to consider odd case as the buffer is always aligned to even.
- if (x < width) {
- u01 = *uSrc;
- v01 = *vSrc;
- y01 = *((uint32_t*)ySrcTop);
- y45 = *((uint32_t*)ySrcBot);
- uv0 = (u01 & 0x3FF) | ((v01 & 0x3FF) << 20);
- *dstTop++ = ((y01 & 0x3FF) << 10) | uv0;
- *dstTop++ = ((y01 >> 16) << 10) | uv0;
- *dstBot++ = ((y45 & 0x3FF) << 10) | uv0;
- *dstBot++ = ((y45 >> 16) << 10) | uv0;
- }
-
- srcY += srcYStride * 2;
- srcU += srcUStride;
- srcV += srcVStride;
- dst += dstStride * 2;
- }
-
- return;
-}
-
-static void convertYUV420Planar16ToYUV420Planar(
- uint8_t *dstY, uint8_t *dstU, uint8_t *dstV,
- const uint16_t *srcY, const uint16_t *srcU, const uint16_t *srcV,
- size_t srcYStride, size_t srcUStride, size_t srcVStride,
- size_t dstYStride, size_t dstUVStride,
- size_t width, size_t height) {
-
- for (size_t y = 0; y < height; ++y) {
- for (size_t x = 0; x < width; ++x) {
- dstY[x] = (uint8_t)(srcY[x] >> 2);
- }
-
- srcY += srcYStride;
- dstY += dstYStride;
- }
-
- for (size_t y = 0; y < (height + 1) / 2; ++y) {
- for (size_t x = 0; x < (width + 1) / 2; ++x) {
- dstU[x] = (uint8_t)(srcU[x] >> 2);
- dstV[x] = (uint8_t)(srcV[x] >> 2);
- }
-
- srcU += srcUStride;
- srcV += srcVStride;
- dstU += dstUVStride;
- dstV += dstUVStride;
- }
- return;
-}
status_t C2SoftVpxDec::outputBuffer(
const std::shared_ptr<C2BlockPool> &pool,
const std::unique_ptr<C2Work> &work)
@@ -804,7 +687,14 @@
if (defaultColorAspects->primaries == C2Color::PRIMARIES_BT2020 &&
defaultColorAspects->matrix == C2Color::MATRIX_BT2020 &&
defaultColorAspects->transfer == C2Color::TRANSFER_ST2084) {
- format = HAL_PIXEL_FORMAT_RGBA_1010102;
+ // TODO (b/201787956) For devices that do not support HAL_PIXEL_FORMAT_RGBA_1010102,
+ // HAL_PIXEL_FORMAT_YV12 is used as a temporary work around.
+ if (!mIsFormatR10G10B10A2Supported) {
+ ALOGE("HAL_PIXEL_FORMAT_RGBA_1010102 isn't supported");
+ format = HAL_PIXEL_FORMAT_YV12;
+ } else {
+ format = HAL_PIXEL_FORMAT_RGBA_1010102;
+ }
}
}
C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
@@ -867,24 +757,22 @@
queue->cond.signal();
queue.waitForCondition(queue->cond);
}
+ } else if (format == HAL_PIXEL_FORMAT_YCBCR_P010) {
+ convertYUV420Planar16ToP010((uint16_t *)dstY, (uint16_t *)dstU, srcY, srcU, srcV,
+ srcYStride / 2, srcUStride / 2, srcVStride / 2,
+ dstYStride / 2, dstUVStride / 2, mWidth, mHeight);
} else {
- convertYUV420Planar16ToYUV420Planar(dstY, dstU, dstV,
- srcY, srcU, srcV,
- srcYStride / 2, srcUStride / 2, srcVStride / 2,
- dstYStride, dstUVStride,
- mWidth, mHeight);
+ convertYUV420Planar16ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride / 2,
+ srcUStride / 2, srcVStride / 2, dstYStride, dstUVStride,
+ mWidth, mHeight);
}
} else {
const uint8_t *srcY = (const uint8_t *)img->planes[VPX_PLANE_Y];
const uint8_t *srcU = (const uint8_t *)img->planes[VPX_PLANE_U];
const uint8_t *srcV = (const uint8_t *)img->planes[VPX_PLANE_V];
- copyOutputBufferToYuvPlanarFrame(
- dstY, dstU, dstV,
- srcY, srcU, srcV,
- srcYStride, srcUStride, srcVStride,
- dstYStride, dstUVStride,
- mWidth, mHeight);
+ convertYUV420Planar8ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride, srcUStride,
+ srcVStride, dstYStride, dstUVStride, mWidth, mHeight);
}
finishWork(((c2_cntr64_t *)img->user_priv)->peekull(), work, std::move(block));
return OK;
diff --git a/media/codec2/components/vpx/C2SoftVpxDec.h b/media/codec2/components/vpx/C2SoftVpxDec.h
index 2065165..ade162d 100644
--- a/media/codec2/components/vpx/C2SoftVpxDec.h
+++ b/media/codec2/components/vpx/C2SoftVpxDec.h
@@ -80,7 +80,7 @@
};
std::shared_ptr<Mutexed<ConversionQueue>> mQueue;
std::vector<sp<ConverterThread>> mConverterThreads;
-
+ bool mIsFormatR10G10B10A2Supported;
status_t initDecoder();
status_t destroyDecoder();
void finishWork(uint64_t index, const std::unique_ptr<C2Work> &work,
diff --git a/media/codec2/core/include/C2Config.h b/media/codec2/core/include/C2Config.h
index feaa98c..16e507c 100644
--- a/media/codec2/core/include/C2Config.h
+++ b/media/codec2/core/include/C2Config.h
@@ -59,6 +59,7 @@
enum drc_compression_mode_t : int32_t; ///< DRC compression mode
enum drc_effect_type_t : int32_t; ///< DRC effect type
enum drc_album_mode_t : int32_t; ///< DRC album mode
+ enum hdr_dynamic_metadata_type_t : uint32_t; ///< HDR dynamic metadata type
enum intra_refresh_mode_t : uint32_t; ///< intra refresh modes
enum level_t : uint32_t; ///< coding level
enum ordinal_key_t : uint32_t; ///< work ordering keys
@@ -189,10 +190,13 @@
kParamIndexPictureTypeMask,
kParamIndexPictureType,
+ // deprecated
kParamIndexHdr10PlusMetadata,
kParamIndexPictureQuantization,
+ kParamIndexHdrDynamicMetadata,
+
/* ------------------------------------ video components ------------------------------------ */
kParamIndexFrameRate = C2_PARAM_INDEX_VIDEO_PARAM_START,
@@ -270,6 +274,9 @@
// encoding quality requirements
kParamIndexEncodingQualityLevel, // encoders, enum
+
+ // encoding statistics, average block qp of a frame
+ kParamIndexAverageBlockQuantization, // int32
};
}
@@ -1602,16 +1609,54 @@
C2FIELD(maxFall, "max-fall")
};
typedef C2StreamParam<C2Info, C2HdrStaticMetadataStruct, kParamIndexHdrStaticMetadata>
- C2StreamHdrStaticInfo;
+ C2StreamHdrStaticMetadataInfo;
+typedef C2StreamParam<C2Info, C2HdrStaticMetadataStruct, kParamIndexHdrStaticMetadata>
+ C2StreamHdrStaticInfo; // deprecated
constexpr char C2_PARAMKEY_HDR_STATIC_INFO[] = "raw.hdr-static-info";
/**
* HDR10+ Metadata Info.
+ *
+ * Deprecated. Use C2StreamHdrDynamicMetadataInfo with
+ * HDR_DYNAMIC_METADATA_TYPE_SMPTE_2094_40
*/
typedef C2StreamParam<C2Info, C2BlobValue, kParamIndexHdr10PlusMetadata>
- C2StreamHdr10PlusInfo;
-constexpr char C2_PARAMKEY_INPUT_HDR10_PLUS_INFO[] = "input.hdr10-plus-info";
-constexpr char C2_PARAMKEY_OUTPUT_HDR10_PLUS_INFO[] = "output.hdr10-plus-info";
+ C2StreamHdr10PlusInfo; // deprecated
+constexpr char C2_PARAMKEY_INPUT_HDR10_PLUS_INFO[] = "input.hdr10-plus-info"; // deprecated
+constexpr char C2_PARAMKEY_OUTPUT_HDR10_PLUS_INFO[] = "output.hdr10-plus-info"; // deprecated
+
+/**
+ * HDR dynamic metadata types
+ */
+C2ENUM(C2Config::hdr_dynamic_metadata_type_t, uint32_t,
+ HDR_DYNAMIC_METADATA_TYPE_SMPTE_2094_10, ///< SMPTE ST 2094-10
+ HDR_DYNAMIC_METADATA_TYPE_SMPTE_2094_40, ///< SMPTE ST 2094-40
+)
+
+struct C2HdrDynamicMetadataStruct {
+ inline C2HdrDynamicMetadataStruct() { memset(this, 0, sizeof(*this)); }
+
+ inline C2HdrDynamicMetadataStruct(
+ size_t flexCount, C2Config::hdr_dynamic_metadata_type_t type)
+ : type_(type) {
+ memset(data, 0, flexCount);
+ }
+
+ C2Config::hdr_dynamic_metadata_type_t type_;
+ uint8_t data[];
+
+ DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(HdrDynamicMetadata, data)
+ C2FIELD(type_, "type")
+ C2FIELD(data, "data")
+};
+
+/**
+ * Dynamic HDR Metadata Info.
+ */
+typedef C2StreamParam<C2Info, C2HdrDynamicMetadataStruct, kParamIndexHdrDynamicMetadata>
+ C2StreamHdrDynamicMetadataInfo;
+constexpr char C2_PARAMKEY_INPUT_HDR_DYNAMIC_INFO[] = "input.hdr-dynamic-info";
+constexpr char C2_PARAMKEY_OUTPUT_HDR_DYNAMIC_INFO[] = "output.hdr-dynamic-info";
/* ------------------------------------ block-based coding ----------------------------------- */
@@ -2411,6 +2456,17 @@
S_HANDHELD = 1 // corresponds to VMAF=70
);
+/**
+ * Video Encoding Statistics Export
+ */
+
+/**
+ * Average block QP exported from video encoder.
+ */
+typedef C2StreamParam<C2Info, C2SimpleValueStruct<int32_t>, kParamIndexAverageBlockQuantization>
+ C2AndroidStreamAverageBlockQuantizationInfo;
+constexpr char C2_PARAMKEY_AVERAGE_QP[] = "coded.average-qp";
+
/// @}
#endif // C2CONFIG_H_
diff --git a/media/codec2/hidl/plugin/FilterWrapper.cpp b/media/codec2/hidl/plugin/FilterWrapper.cpp
index 70c63f2..d5124fd 100644
--- a/media/codec2/hidl/plugin/FilterWrapper.cpp
+++ b/media/codec2/hidl/plugin/FilterWrapper.cpp
@@ -49,6 +49,11 @@
std::weak_ptr<FilterWrapper> filterWrapper)
: mIntf(intf), mFilterWrapper(filterWrapper) {
takeFilters(std::move(filters));
+ for (size_t i = 0; i < mFilters.size(); ++i) {
+ mControlParamTypes.insert(
+ mFilters[i].desc.controlParams.begin(),
+ mFilters[i].desc.controlParams.end());
+ }
}
~WrappedDecoderInterface() override = default;
@@ -187,7 +192,12 @@
}
std::vector<C2Param *> stackParamsForIntf;
- std::copy_n(stackParamsList.begin(), stackParamsList.size(), stackParamsForIntf.begin());
+ for (C2Param *param : stackParamsList) {
+ if (mControlParamTypes.count(param->type()) != 0) {
+ continue;
+ }
+ stackParamsForIntf.push_back(param);
+ }
// Gather heap params that did not get queried from the filter interfaces above.
// These need to be queried from the decoder interface.
@@ -197,6 +207,9 @@
if (mTypeToIndexForQuery.find(type) != mTypeToIndexForQuery.end()) {
continue;
}
+ if (mControlParamTypes.count(type) != 0) {
+ continue;
+ }
heapParamIndicesForIntf.push_back(heapParamIndices[j]);
}
@@ -251,11 +264,14 @@
std::vector<C2Param *> paramsForFilter;
for (C2Param* param : params) {
auto it = mTypeToIndexForConfig.find(param->type().type());
- if (it != mTypeToIndexForConfig.end() && it->second != i) {
+ if (it == mTypeToIndexForConfig.end() || it->second != i) {
continue;
}
paramsForFilter.push_back(param);
}
+ if (paramsForFilter.empty()) {
+ continue;
+ }
c2_status_t err = filter->config_vb(paramsForFilter, mayBlock, &filterFailures);
if (err != C2_OK) {
LOG(err == C2_BAD_INDEX ? VERBOSE : WARNING)
@@ -356,6 +372,7 @@
std::weak_ptr<FilterWrapper> mFilterWrapper;
std::map<uint32_t, size_t> mTypeToIndexForQuery;
std::map<uint32_t, size_t> mTypeToIndexForConfig;
+ std::set<C2Param::Type> mControlParamTypes;
c2_status_t transferParams_l(
const std::shared_ptr<C2ComponentInterface> &curr,
@@ -430,6 +447,10 @@
LOG(DEBUG) << "WrappedDecoderInterface: FilterWrapper not found";
return C2_OK;
}
+ if (!filterWrapper->isFilteringEnabled(next)) {
+ LOG(VERBOSE) << "WrappedDecoderInterface: filtering not enabled";
+ return C2_OK;
+ }
std::vector<std::unique_ptr<C2Param>> params;
c2_status_t err = filterWrapper->queryParamsForPreviousComponent(next, ¶ms);
if (err != C2_OK) {
@@ -594,6 +615,8 @@
}
}
mRunningFilters.clear();
+ std::vector<FilterWrapper::Component> filters(mFilters);
+ mIntf->takeFilters(std::move(filters));
return result;
}
diff --git a/media/codec2/sfplugin/Android.bp b/media/codec2/sfplugin/Android.bp
index 2bc748f..feeddb5 100644
--- a/media/codec2/sfplugin/Android.bp
+++ b/media/codec2/sfplugin/Android.bp
@@ -42,12 +42,14 @@
"android.hardware.drm@1.0",
"android.hardware.media.c2@1.0",
"android.hardware.media.omx@1.0",
+ "android.hardware.graphics.mapper@4.0",
"libbase",
"libbinder",
"libcodec2",
"libcodec2_client",
"libcodec2_vndk",
"libcutils",
+ "libgralloctypes",
"libgui",
"libhidlallocatorutils",
"libhidlbase",
diff --git a/media/codec2/sfplugin/C2OMXNode.cpp b/media/codec2/sfplugin/C2OMXNode.cpp
index c049187..ed7d69c 100644
--- a/media/codec2/sfplugin/C2OMXNode.cpp
+++ b/media/codec2/sfplugin/C2OMXNode.cpp
@@ -42,6 +42,7 @@
#include "utils/Codec2Mapper.h"
#include "C2OMXNode.h"
+#include "Codec2Buffer.h"
namespace android {
@@ -466,6 +467,18 @@
new Buffer2D(block->share(
C2Rect(block->width(), block->height()), ::C2Fence())));
work->input.buffers.push_back(c2Buffer);
+ std::shared_ptr<C2StreamHdrStaticInfo::input> staticInfo;
+ std::shared_ptr<C2StreamHdrDynamicMetadataInfo::input> dynamicInfo;
+ GetHdrMetadataFromGralloc4Handle(
+ block->handle(),
+ &staticInfo,
+ &dynamicInfo);
+ if (staticInfo && *staticInfo) {
+ c2Buffer->setInfo(staticInfo);
+ }
+ if (dynamicInfo && *dynamicInfo) {
+ c2Buffer->setInfo(dynamicInfo);
+ }
}
work->worklets.clear();
work->worklets.emplace_back(new C2Worklet);
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 44a2c5b..1f8b33d 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -1213,11 +1213,25 @@
std::initializer_list<C2Param::Index> indices {
colorAspectsRequestIndex.withStream(0u),
};
- c2_status_t c2err = comp->query(
- { &usage, &maxInputSize, &prepend },
- indices,
- C2_DONT_BLOCK,
- ¶ms);
+ int32_t colorTransferRequest = 0;
+ if (config->mDomain & (Config::IS_IMAGE | Config::IS_VIDEO)
+ && !sdkParams->findInt32("color-transfer-request", &colorTransferRequest)) {
+ colorTransferRequest = 0;
+ }
+ c2_status_t c2err = C2_OK;
+ if (colorTransferRequest != 0) {
+ c2err = comp->query(
+ { &usage, &maxInputSize, &prepend },
+ indices,
+ C2_DONT_BLOCK,
+ ¶ms);
+ } else {
+ c2err = comp->query(
+ { &usage, &maxInputSize, &prepend },
+ {},
+ C2_DONT_BLOCK,
+ ¶ms);
+ }
if (c2err != C2_OK && c2err != C2_BAD_INDEX) {
ALOGE("Failed to query component interface: %d", c2err);
return UNKNOWN_ERROR;
@@ -1360,11 +1374,6 @@
colorTransferRequestParam = std::move(param);
}
}
- int32_t colorTransferRequest = 0;
- if (config->mDomain & (Config::IS_IMAGE | Config::IS_VIDEO)
- && !sdkParams->findInt32("color-transfer-request", &colorTransferRequest)) {
- colorTransferRequest = 0;
- }
if (colorTransferRequest != 0) {
if (colorTransferRequestParam && *colorTransferRequestParam) {
@@ -1434,6 +1443,27 @@
config->mOutputFormat->setInt32("android._tunneled", 1);
}
+ // Convert an encoding statistics level to corresponding encoding statistics
+ // kinds
+ int32_t encodingStatisticsLevel = VIDEO_ENCODING_STATISTICS_LEVEL_NONE;
+ if ((config->mDomain & Config::IS_ENCODER)
+ && (config->mDomain & Config::IS_VIDEO)
+ && msg->findInt32(KEY_VIDEO_ENCODING_STATISTICS_LEVEL, &encodingStatisticsLevel)) {
+ // Higher level include all the enc stats belong to lower level.
+ switch (encodingStatisticsLevel) {
+ // case VIDEO_ENCODING_STATISTICS_LEVEL_2: // reserved for the future level 2
+ // with more enc stat kinds
+ // Future extended encoding statistics for the level 2 should be added here
+ case VIDEO_ENCODING_STATISTICS_LEVEL_1:
+ config->subscribeToConfigUpdate(comp,
+ {kParamIndexAverageBlockQuantization, kParamIndexPictureType});
+ break;
+ case VIDEO_ENCODING_STATISTICS_LEVEL_NONE:
+ break;
+ }
+ }
+ ALOGD("encoding statistics level = %d", encodingStatisticsLevel);
+
ALOGD("setup formats input: %s",
config->mInputFormat->debugString().c_str());
ALOGD("setup formats output: %s",
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 23a326f..99aa593 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -840,6 +840,35 @@
hdr10PlusInfo.reset();
}
+ // HDR dynamic info
+ std::shared_ptr<const C2StreamHdrDynamicMetadataInfo::output> hdrDynamicInfo =
+ std::static_pointer_cast<const C2StreamHdrDynamicMetadataInfo::output>(
+ c2Buffer->getInfo(C2StreamHdrDynamicMetadataInfo::output::PARAM_TYPE));
+ // TODO: make this sticky & enable unset
+ if (hdrDynamicInfo && hdrDynamicInfo->flexCount() == 0) {
+ hdrDynamicInfo.reset();
+ }
+
+ if (hdr10PlusInfo) {
+ // C2StreamHdr10PlusInfo is deprecated; components should use
+ // C2StreamHdrDynamicMetadataInfo
+ // TODO: #metric
+ if (hdrDynamicInfo) {
+ // It is unexpected that C2StreamHdr10PlusInfo and
+ // C2StreamHdrDynamicMetadataInfo is both present.
+ // C2StreamHdrDynamicMetadataInfo takes priority.
+ // TODO: #metric
+ } else {
+ std::shared_ptr<C2StreamHdrDynamicMetadataInfo::output> info =
+ C2StreamHdrDynamicMetadataInfo::output::AllocShared(
+ hdr10PlusInfo->flexCount(),
+ 0u,
+ C2Config::HDR_DYNAMIC_METADATA_TYPE_SMPTE_2094_40);
+ memcpy(info->m.data, hdr10PlusInfo->m.value, hdr10PlusInfo->flexCount());
+ hdrDynamicInfo = info;
+ }
+ }
+
std::vector<C2ConstGraphicBlock> blocks = c2Buffer->data().graphicBlocks();
if (blocks.size() != 1u) {
ALOGD("[%s] expected 1 graphic block, but got %zu", mName, blocks.size());
@@ -859,7 +888,7 @@
videoScalingMode,
transform,
Fence::NO_FENCE, 0);
- if (hdrStaticInfo || hdr10PlusInfo) {
+ if (hdrStaticInfo || hdrDynamicInfo) {
HdrMetadata hdr;
if (hdrStaticInfo) {
// If mastering max and min luminance fields are 0, do not use them.
@@ -896,13 +925,16 @@
hdr.cta8613 = cta861_meta;
}
}
- if (hdr10PlusInfo) {
+ if (hdrDynamicInfo
+ && hdrDynamicInfo->m.type_ == C2Config::HDR_DYNAMIC_METADATA_TYPE_SMPTE_2094_40) {
hdr.validTypes |= HdrMetadata::HDR10PLUS;
hdr.hdr10plus.assign(
- hdr10PlusInfo->m.value,
- hdr10PlusInfo->m.value + hdr10PlusInfo->flexCount());
+ hdrDynamicInfo->m.data,
+ hdrDynamicInfo->m.data + hdrDynamicInfo->flexCount());
}
qbi.setHdrMetadata(hdr);
+
+ SetHdrMetadataToGralloc4Handle(hdrStaticInfo, hdrDynamicInfo, block.handle());
}
// we don't have dirty regions
qbi.setSurfaceDamage(Region::INVALID_REGION);
@@ -1467,6 +1499,16 @@
std::list<std::unique_ptr<C2Work>> flushedConfigs;
mFlushedConfigs.lock()->swap(flushedConfigs);
if (!flushedConfigs.empty()) {
+ {
+ Mutexed<PipelineWatcher>::Locked watcher(mPipelineWatcher);
+ PipelineWatcher::Clock::time_point now = PipelineWatcher::Clock::now();
+ for (const std::unique_ptr<C2Work> &work : flushedConfigs) {
+ watcher->onWorkQueued(
+ work->input.ordinal.frameIndex.peeku(),
+ std::vector(work->input.buffers),
+ now);
+ }
+ }
err = mComponent->queue(&flushedConfigs);
if (err != C2_OK) {
ALOGW("[%s] Error while queueing a flushed config", mName);
@@ -1533,41 +1575,45 @@
setDescrambler(nullptr);
}
-
void CCodecBufferChannel::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
ALOGV("[%s] flush", mName);
- std::vector<uint64_t> indices;
std::list<std::unique_ptr<C2Work>> configs;
mInput.lock()->lastFlushIndex = mFrameIndex.load(std::memory_order_relaxed);
- for (const std::unique_ptr<C2Work> &work : flushedWork) {
- indices.push_back(work->input.ordinal.frameIndex.peeku());
- if (!(work->input.flags & C2FrameData::FLAG_CODEC_CONFIG)) {
- continue;
+ {
+ Mutexed<PipelineWatcher>::Locked watcher(mPipelineWatcher);
+ for (const std::unique_ptr<C2Work> &work : flushedWork) {
+ uint64_t frameIndex = work->input.ordinal.frameIndex.peeku();
+ if (!(work->input.flags & C2FrameData::FLAG_CODEC_CONFIG)) {
+ watcher->onWorkDone(frameIndex);
+ continue;
+ }
+ if (work->input.buffers.empty()
+ || work->input.buffers.front() == nullptr
+ || work->input.buffers.front()->data().linearBlocks().empty()) {
+ ALOGD("[%s] no linear codec config data found", mName);
+ watcher->onWorkDone(frameIndex);
+ continue;
+ }
+ std::unique_ptr<C2Work> copy(new C2Work);
+ copy->input.flags = C2FrameData::flags_t(
+ work->input.flags | C2FrameData::FLAG_DROP_FRAME);
+ copy->input.ordinal = work->input.ordinal;
+ copy->input.ordinal.frameIndex = mFrameIndex++;
+ for (size_t i = 0; i < work->input.buffers.size(); ++i) {
+ copy->input.buffers.push_back(watcher->onInputBufferReleased(frameIndex, i));
+ }
+ for (const std::unique_ptr<C2Param> ¶m : work->input.configUpdate) {
+ copy->input.configUpdate.push_back(C2Param::Copy(*param));
+ }
+ copy->input.infoBuffers.insert(
+ copy->input.infoBuffers.begin(),
+ work->input.infoBuffers.begin(),
+ work->input.infoBuffers.end());
+ copy->worklets.emplace_back(new C2Worklet);
+ configs.push_back(std::move(copy));
+ watcher->onWorkDone(frameIndex);
+ ALOGV("[%s] stashed flushed codec config data", mName);
}
- if (work->input.buffers.empty()
- || work->input.buffers.front() == nullptr
- || work->input.buffers.front()->data().linearBlocks().empty()) {
- ALOGD("[%s] no linear codec config data found", mName);
- continue;
- }
- std::unique_ptr<C2Work> copy(new C2Work);
- copy->input.flags = C2FrameData::flags_t(work->input.flags | C2FrameData::FLAG_DROP_FRAME);
- copy->input.ordinal = work->input.ordinal;
- copy->input.ordinal.frameIndex = mFrameIndex++;
- copy->input.buffers.insert(
- copy->input.buffers.begin(),
- work->input.buffers.begin(),
- work->input.buffers.end());
- for (const std::unique_ptr<C2Param> ¶m : work->input.configUpdate) {
- copy->input.configUpdate.push_back(C2Param::Copy(*param));
- }
- copy->input.infoBuffers.insert(
- copy->input.infoBuffers.begin(),
- work->input.infoBuffers.begin(),
- work->input.infoBuffers.end());
- copy->worklets.emplace_back(new C2Worklet);
- configs.push_back(std::move(copy));
- ALOGV("[%s] stashed flushed codec config data", mName);
}
mFlushedConfigs.lock()->swap(configs);
{
@@ -1582,12 +1628,6 @@
output->buffers->flushStash();
}
}
- {
- Mutexed<PipelineWatcher>::Locked watcher(mPipelineWatcher);
- for (uint64_t index : indices) {
- watcher->onWorkDone(index);
- }
- }
}
void CCodecBufferChannel::onWorkDone(
diff --git a/media/codec2/sfplugin/CCodecConfig.cpp b/media/codec2/sfplugin/CCodecConfig.cpp
index 03418d9..0899e99 100644
--- a/media/codec2/sfplugin/CCodecConfig.cpp
+++ b/media/codec2/sfplugin/CCodecConfig.cpp
@@ -953,6 +953,12 @@
return value == 0 ? C2_FALSE : C2_TRUE;
}));
+ add(ConfigMapper(KEY_VIDEO_QP_AVERAGE, C2_PARAMKEY_AVERAGE_QP, "value")
+ .limitTo(D::ENCODER & D::VIDEO & D::READ));
+
+ add(ConfigMapper(KEY_PICTURE_TYPE, C2_PARAMKEY_PICTURE_TYPE, "value")
+ .limitTo(D::ENCODER & D::VIDEO & D::READ));
+
/* still to do
constexpr char KEY_PUSH_BLANK_BUFFERS_ON_STOP[] = "push-blank-buffers-on-shutdown";
diff --git a/media/codec2/sfplugin/CCodecConfig.h b/media/codec2/sfplugin/CCodecConfig.h
index 417b773..88e6239 100644
--- a/media/codec2/sfplugin/CCodecConfig.h
+++ b/media/codec2/sfplugin/CCodecConfig.h
@@ -363,11 +363,6 @@
const std::vector<std::string> &names,
c2_blocking_t blocking = C2_DONT_BLOCK);
-private:
-
- /// initializes the standard MediaCodec to Codec 2.0 params mapping
- void initializeStandardParams();
-
/// Adds indices to the subscribed indices, and updated subscription to component
/// \param blocking blocking mode to use with the component
status_t subscribeToConfigUpdate(
@@ -375,6 +370,11 @@
const std::vector<C2Param::Index> &indices,
c2_blocking_t blocking = C2_DONT_BLOCK);
+private:
+
+ /// initializes the standard MediaCodec to Codec 2.0 params mapping
+ void initializeStandardParams();
+
/// Gets SDK format from codec 2.0 reflected configuration
/// \param domain input/output bitmask
sp<AMessage> getFormatForDomain(
diff --git a/media/codec2/sfplugin/Codec2Buffer.cpp b/media/codec2/sfplugin/Codec2Buffer.cpp
index 4070478..7f9de21 100644
--- a/media/codec2/sfplugin/Codec2Buffer.cpp
+++ b/media/codec2/sfplugin/Codec2Buffer.cpp
@@ -18,9 +18,14 @@
#define LOG_TAG "Codec2Buffer"
#include <utils/Log.h>
+#include <aidl/android/hardware/graphics/common/Cta861_3.h>
+#include <aidl/android/hardware/graphics/common/Smpte2086.h>
#include <android-base/properties.h>
#include <android/hardware/cas/native/1.0/types.h>
#include <android/hardware/drm/1.0/types.h>
+#include <android/hardware/graphics/common/1.2/types.h>
+#include <android/hardware/graphics/mapper/4.0/IMapper.h>
+#include <gralloctypes/Gralloc4.h>
#include <hidlmemory/FrameworkUtils.h>
#include <media/hardware/HardwareAPI.h>
#include <media/stagefright/CodecBase.h>
@@ -941,4 +946,218 @@
return const_cast<native_handle_t *>(mBlock->handle());
}
+using ::aidl::android::hardware::graphics::common::Cta861_3;
+using ::aidl::android::hardware::graphics::common::Smpte2086;
+
+using ::android::gralloc4::MetadataType_Cta861_3;
+using ::android::gralloc4::MetadataType_Smpte2086;
+using ::android::gralloc4::MetadataType_Smpte2094_40;
+
+using ::android::hardware::Return;
+using ::android::hardware::hidl_vec;
+
+using Error4 = ::android::hardware::graphics::mapper::V4_0::Error;
+using IMapper4 = ::android::hardware::graphics::mapper::V4_0::IMapper;
+
+namespace {
+
+sp<IMapper4> GetMapper4() {
+ static sp<IMapper4> sMapper = IMapper4::getService();
+ return sMapper;
+}
+
+class NativeHandleDeleter {
+public:
+ explicit NativeHandleDeleter(native_handle_t *handle) : mHandle(handle) {}
+ ~NativeHandleDeleter() {
+ if (mHandle) {
+ native_handle_delete(mHandle);
+ }
+ }
+private:
+ native_handle_t *mHandle;
+};
+
+} // namspace
+
+c2_status_t GetHdrMetadataFromGralloc4Handle(
+ const C2Handle *const handle,
+ std::shared_ptr<C2StreamHdrStaticMetadataInfo::input> *staticInfo,
+ std::shared_ptr<C2StreamHdrDynamicMetadataInfo::input> *dynamicInfo) {
+ c2_status_t err = C2_OK;
+ native_handle_t *nativeHandle = UnwrapNativeCodec2GrallocHandle(handle);
+ if (nativeHandle == nullptr) {
+ // Nothing to do
+ return err;
+ }
+ // TRICKY: UnwrapNativeCodec2GrallocHandle creates a new handle but
+ // does not clone the fds. Thus we need to delete the handle
+ // without closing it when going out of scope.
+ // NativeHandle cannot solve this problem, as it would close and
+ // delete the handle, while we need delete only.
+ NativeHandleDeleter nhd(nativeHandle);
+ sp<IMapper4> mapper = GetMapper4();
+ if (!mapper) {
+ // Gralloc4 not supported; nothing to do
+ return err;
+ }
+ Error4 mapperErr = Error4::NONE;
+ if (staticInfo) {
+ staticInfo->reset(new C2StreamHdrStaticMetadataInfo::input(0u));
+ memset(&(*staticInfo)->mastering, 0, sizeof((*staticInfo)->mastering));
+ (*staticInfo)->maxCll = 0;
+ (*staticInfo)->maxFall = 0;
+ IMapper4::get_cb cb = [&mapperErr, staticInfo](Error4 err, const hidl_vec<uint8_t> &vec) {
+ mapperErr = err;
+ if (err != Error4::NONE) {
+ return;
+ }
+
+ std::optional<Smpte2086> smpte2086;
+ gralloc4::decodeSmpte2086(vec, &smpte2086);
+ if (smpte2086) {
+ (*staticInfo)->mastering.red.x = smpte2086->primaryRed.x;
+ (*staticInfo)->mastering.red.y = smpte2086->primaryRed.y;
+ (*staticInfo)->mastering.green.x = smpte2086->primaryGreen.x;
+ (*staticInfo)->mastering.green.y = smpte2086->primaryGreen.y;
+ (*staticInfo)->mastering.blue.x = smpte2086->primaryBlue.x;
+ (*staticInfo)->mastering.blue.y = smpte2086->primaryBlue.y;
+ (*staticInfo)->mastering.white.x = smpte2086->whitePoint.x;
+ (*staticInfo)->mastering.white.y = smpte2086->whitePoint.y;
+
+ (*staticInfo)->mastering.maxLuminance = smpte2086->maxLuminance;
+ (*staticInfo)->mastering.minLuminance = smpte2086->minLuminance;
+ } else {
+ mapperErr = Error4::BAD_VALUE;
+ }
+ };
+ Return<void> ret = mapper->get(nativeHandle, MetadataType_Smpte2086, cb);
+ if (!ret.isOk()) {
+ err = C2_REFUSED;
+ } else if (mapperErr != Error4::NONE) {
+ err = C2_CORRUPTED;
+ }
+ cb = [&mapperErr, staticInfo](Error4 err, const hidl_vec<uint8_t> &vec) {
+ mapperErr = err;
+ if (err != Error4::NONE) {
+ return;
+ }
+
+ std::optional<Cta861_3> cta861_3;
+ gralloc4::decodeCta861_3(vec, &cta861_3);
+ if (cta861_3) {
+ (*staticInfo)->maxCll = cta861_3->maxContentLightLevel;
+ (*staticInfo)->maxFall = cta861_3->maxFrameAverageLightLevel;
+ } else {
+ mapperErr = Error4::BAD_VALUE;
+ }
+ };
+ ret = mapper->get(nativeHandle, MetadataType_Cta861_3, cb);
+ if (!ret.isOk()) {
+ err = C2_REFUSED;
+ } else if (mapperErr != Error4::NONE) {
+ err = C2_CORRUPTED;
+ }
+ }
+ if (dynamicInfo) {
+ dynamicInfo->reset();
+ IMapper4::get_cb cb = [&mapperErr, dynamicInfo](Error4 err, const hidl_vec<uint8_t> &vec) {
+ mapperErr = err;
+ if (err != Error4::NONE) {
+ return;
+ }
+ if (!dynamicInfo) {
+ return;
+ }
+ *dynamicInfo = C2StreamHdrDynamicMetadataInfo::input::AllocShared(
+ vec.size(), 0u, C2Config::HDR_DYNAMIC_METADATA_TYPE_SMPTE_2094_40);
+ memcpy((*dynamicInfo)->m.data, vec.data(), vec.size());
+ };
+ Return<void> ret = mapper->get(nativeHandle, MetadataType_Smpte2094_40, cb);
+ if (!ret.isOk() || mapperErr != Error4::NONE) {
+ dynamicInfo->reset();
+ }
+ }
+
+ return err;
+}
+
+c2_status_t SetHdrMetadataToGralloc4Handle(
+ const std::shared_ptr<const C2StreamHdrStaticMetadataInfo::output> &staticInfo,
+ const std::shared_ptr<const C2StreamHdrDynamicMetadataInfo::output> &dynamicInfo,
+ const C2Handle *const handle) {
+ c2_status_t err = C2_OK;
+ native_handle_t *nativeHandle = UnwrapNativeCodec2GrallocHandle(handle);
+ if (nativeHandle == nullptr) {
+ // Nothing to do
+ return err;
+ }
+ // TRICKY: UnwrapNativeCodec2GrallocHandle creates a new handle but
+ // does not clone the fds. Thus we need to delete the handle
+ // without closing it when going out of scope.
+ NativeHandleDeleter nhd(nativeHandle);
+ sp<IMapper4> mapper = GetMapper4();
+ if (!mapper) {
+ // Gralloc4 not supported; nothing to do
+ return err;
+ }
+ if (staticInfo && *staticInfo) {
+ std::optional<Smpte2086> smpte2086 = Smpte2086{
+ {staticInfo->mastering.red.x, staticInfo->mastering.red.y},
+ {staticInfo->mastering.green.x, staticInfo->mastering.green.y},
+ {staticInfo->mastering.blue.x, staticInfo->mastering.blue.y},
+ {staticInfo->mastering.white.x, staticInfo->mastering.white.y},
+ staticInfo->mastering.maxLuminance,
+ staticInfo->mastering.minLuminance,
+ };
+ hidl_vec<uint8_t> vec;
+ if (gralloc4::encodeSmpte2086(smpte2086, &vec) == OK) {
+ Return<Error4> ret = mapper->set(nativeHandle, MetadataType_Smpte2086, vec);
+ if (!ret.isOk()) {
+ err = C2_REFUSED;
+ } else if (ret != Error4::NONE) {
+ err = C2_CORRUPTED;
+ }
+ }
+ std::optional<Cta861_3> cta861_3 = Cta861_3{
+ staticInfo->maxCll,
+ staticInfo->maxFall,
+ };
+ if (gralloc4::encodeCta861_3(cta861_3, &vec) == OK) {
+ Return<Error4> ret = mapper->set(nativeHandle, MetadataType_Cta861_3, vec);
+ if (!ret.isOk()) {
+ err = C2_REFUSED;
+ } else if (ret != Error4::NONE) {
+ err = C2_CORRUPTED;
+ }
+ }
+ }
+ if (dynamicInfo && *dynamicInfo) {
+ hidl_vec<uint8_t> vec;
+ vec.resize(dynamicInfo->flexCount());
+ memcpy(vec.data(), dynamicInfo->m.data, dynamicInfo->flexCount());
+ std::optional<IMapper4::MetadataType> metadataType;
+ switch (dynamicInfo->m.type_) {
+ case C2Config::HDR_DYNAMIC_METADATA_TYPE_SMPTE_2094_10:
+ // TODO
+ break;
+ case C2Config::HDR_DYNAMIC_METADATA_TYPE_SMPTE_2094_40:
+ metadataType = MetadataType_Smpte2094_40;
+ break;
+ }
+ if (metadataType) {
+ Return<Error4> ret = mapper->set(nativeHandle, *metadataType, vec);
+ if (!ret.isOk()) {
+ err = C2_REFUSED;
+ } else if (ret != Error4::NONE) {
+ err = C2_CORRUPTED;
+ }
+ } else {
+ err = C2_BAD_VALUE;
+ }
+ }
+
+ return err;
+}
+
} // namespace android
diff --git a/media/codec2/sfplugin/Codec2Buffer.h b/media/codec2/sfplugin/Codec2Buffer.h
index dc788cd..b02b042 100644
--- a/media/codec2/sfplugin/Codec2Buffer.h
+++ b/media/codec2/sfplugin/Codec2Buffer.h
@@ -19,6 +19,7 @@
#define CODEC2_BUFFER_H_
#include <C2Buffer.h>
+#include <C2Config.h>
#include <binder/IMemory.h>
#include <media/hardware/VideoAPI.h>
@@ -391,6 +392,36 @@
int32_t mHeapSeqNum;
};
+/**
+ * Get HDR metadata from Gralloc4 handle.
+ *
+ * \param[in] handle handle of the allocation
+ * \param[out] staticInfo HDR static info to be filled. Ignored if null;
+ * if |handle| is invalid or does not contain the metadata,
+ * the shared_ptr is reset.
+ * \param[out] dynamicInfo HDR dynamic info to be filled. Ignored if null;
+ * if |handle| is invalid or does not contain the metadata,
+ * the shared_ptr is reset.
+ * \return C2_OK if successful
+ */
+c2_status_t GetHdrMetadataFromGralloc4Handle(
+ const C2Handle *const handle,
+ std::shared_ptr<C2StreamHdrStaticMetadataInfo::input> *staticInfo,
+ std::shared_ptr<C2StreamHdrDynamicMetadataInfo::input> *dynamicInfo);
+
+/**
+ * Set HDR metadata to Gralloc4 handle.
+ *
+ * \param[in] staticInfo HDR static info to set. Ignored if null or invalid.
+ * \param[in] dynamicInfo HDR dynamic info to set. Ignored if null or invalid.
+ * \param[out] handle handle of the allocation.
+ * \return C2_OK if successful
+ */
+c2_status_t SetHdrMetadataToGralloc4Handle(
+ const std::shared_ptr<const C2StreamHdrStaticMetadataInfo::output> &staticInfo,
+ const std::shared_ptr<const C2StreamHdrDynamicMetadataInfo::output> &dynamicInfo,
+ const C2Handle *const handle);
+
} // namespace android
#endif // CODEC2_BUFFER_H_
diff --git a/media/codec2/sfplugin/tests/CCodecConfig_test.cpp b/media/codec2/sfplugin/tests/CCodecConfig_test.cpp
index 7c660dc..3615289 100644
--- a/media/codec2/sfplugin/tests/CCodecConfig_test.cpp
+++ b/media/codec2/sfplugin/tests/CCodecConfig_test.cpp
@@ -224,6 +224,17 @@
Copy<C2StreamBitrateInfo::output, C2StreamBitrateInfo::input>,
mInputBitrate)
.build());
+
+ addParameter(
+ DefineParam(mOutputProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
+ .withDefault(new C2StreamProfileLevelInfo::output(
+ 0u, PROFILE_UNUSED, LEVEL_UNUSED))
+ .withFields({
+ C2F(mOutputProfileLevel, profile).any(),
+ C2F(mOutputProfileLevel, level).any(),
+ })
+ .withSetter(Setter<C2StreamProfileLevelInfo::output>)
+ .build());
}
// TODO: more SDK params
@@ -241,6 +252,8 @@
std::shared_ptr<C2StreamPixelAspectRatioInfo::output> mPixelAspectRatio;
std::shared_ptr<C2StreamBitrateInfo::input> mInputBitrate;
std::shared_ptr<C2StreamBitrateInfo::output> mOutputBitrate;
+ std::shared_ptr<C2StreamProfileLevelInfo::input> mInputProfileLevel;
+ std::shared_ptr<C2StreamProfileLevelInfo::output> mOutputProfileLevel;
template<typename T>
static C2R Setter(bool, C2P<T> &) {
@@ -576,4 +589,51 @@
<< "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
}
+typedef std::tuple<std::string, C2Config::profile_t, int32_t> HdrProfilesParams;
+
+class HdrProfilesTest
+ : public CCodecConfigTest,
+ public ::testing::WithParamInterface<HdrProfilesParams> {
+};
+
+TEST_P(HdrProfilesTest, SetFromSdk) {
+ HdrProfilesParams params = GetParam();
+ std::string mediaType = std::get<0>(params);
+ C2Config::profile_t c2Profile = std::get<1>(params);
+ int32_t sdkProfile = std::get<2>(params);
+
+ init(C2Component::DOMAIN_VIDEO, C2Component::KIND_ENCODER, mediaType.c_str());
+
+ ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
+
+ sp<AMessage> format{new AMessage};
+ format->setInt32(KEY_PROFILE, sdkProfile);
+
+ std::vector<std::unique_ptr<C2Param>> configUpdate;
+ ASSERT_EQ(OK, mConfig.getConfigUpdateFromSdkParams(
+ mConfigurable, format, D::ALL, C2_MAY_BLOCK, &configUpdate));
+
+ ASSERT_EQ(1u, configUpdate.size());
+ C2StreamProfileLevelInfo::input *pl =
+ FindParam<std::remove_pointer<decltype(pl)>::type>(configUpdate);
+ ASSERT_NE(nullptr, pl);
+ ASSERT_EQ(c2Profile, pl->profile);
+}
+
+HdrProfilesParams kHdrProfilesParams[] = {
+ std::make_tuple(MIMETYPE_VIDEO_HEVC, PROFILE_HEVC_MAIN_10, HEVCProfileMain10HDR10),
+ std::make_tuple(MIMETYPE_VIDEO_HEVC, PROFILE_HEVC_MAIN_10, HEVCProfileMain10HDR10Plus),
+ std::make_tuple(MIMETYPE_VIDEO_VP9, PROFILE_VP9_2, VP9Profile2HDR),
+ std::make_tuple(MIMETYPE_VIDEO_VP9, PROFILE_VP9_2, VP9Profile2HDR10Plus),
+ std::make_tuple(MIMETYPE_VIDEO_VP9, PROFILE_VP9_3, VP9Profile3HDR),
+ std::make_tuple(MIMETYPE_VIDEO_VP9, PROFILE_VP9_3, VP9Profile3HDR10Plus),
+ std::make_tuple(MIMETYPE_VIDEO_AV1, PROFILE_AV1_0, AV1ProfileMain10HDR10),
+ std::make_tuple(MIMETYPE_VIDEO_AV1, PROFILE_AV1_0, AV1ProfileMain10HDR10Plus),
+};
+
+INSTANTIATE_TEST_SUITE_P(
+ CCodecConfig,
+ HdrProfilesTest,
+ ::testing::ValuesIn(kHdrProfilesParams));
+
} // namespace android
diff --git a/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp b/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp
index 5f87c66..2213001 100644
--- a/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp
+++ b/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp
@@ -118,6 +118,22 @@
} // namespace
+bool IsFormatR10G10B10A2SupportedForLegacyRendering() {
+ const AHardwareBuffer_Desc desc = {
+ .width = 320,
+ .height = 240,
+ .format = AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM,
+ .layers = 1,
+ .usage = AHARDWAREBUFFER_USAGE_CPU_READ_RARELY | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN |
+ AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE,
+ .stride = 0,
+ .rfu0 = 0,
+ .rfu1 = 0,
+ };
+
+ return AHardwareBuffer_isSupported(&desc);
+}
+
status_t ImageCopy(uint8_t *imgBase, const MediaImage2 *img, const C2GraphicView &view) {
if (view.crop().width != img->mWidth || view.crop().height != img->mHeight) {
return BAD_VALUE;
diff --git a/media/codec2/sfplugin/utils/Codec2BufferUtils.h b/media/codec2/sfplugin/utils/Codec2BufferUtils.h
index 9fa642d..c4651a4 100644
--- a/media/codec2/sfplugin/utils/Codec2BufferUtils.h
+++ b/media/codec2/sfplugin/utils/Codec2BufferUtils.h
@@ -27,6 +27,11 @@
namespace android {
/**
+ * Check if R10G10B10A2 is supported in legacy rendering path that involves GPU
+ */
+bool IsFormatR10G10B10A2SupportedForLegacyRendering();
+
+/**
* Converts an RGB view to planar YUV 420 media image.
*
* \param dstY pointer to media image buffer
diff --git a/media/codec2/sfplugin/utils/Codec2Mapper.cpp b/media/codec2/sfplugin/utils/Codec2Mapper.cpp
index ca6a328..f557830 100644
--- a/media/codec2/sfplugin/utils/Codec2Mapper.cpp
+++ b/media/codec2/sfplugin/utils/Codec2Mapper.cpp
@@ -255,6 +255,8 @@
{ C2Config::PROFILE_HEVC_MAIN_STILL, HEVCProfileMainStill },
{ C2Config::PROFILE_HEVC_MAIN_INTRA, HEVCProfileMain },
{ C2Config::PROFILE_HEVC_MAIN_10_INTRA, HEVCProfileMain10 },
+ { C2Config::PROFILE_HEVC_MAIN_10, HEVCProfileMain10HDR10 },
+ { C2Config::PROFILE_HEVC_MAIN_10, HEVCProfileMain10HDR10Plus },
};
ALookup<C2Config::profile_t, int32_t> sHevcHdrProfiles = {
diff --git a/media/codec2/vndk/C2AllocatorIon.cpp b/media/codec2/vndk/C2AllocatorIon.cpp
index 77b265a..7b593ee 100644
--- a/media/codec2/vndk/C2AllocatorIon.cpp
+++ b/media/codec2/vndk/C2AllocatorIon.cpp
@@ -207,6 +207,7 @@
c2_status_t err = mapInternal(mapSize, mapOffset, alignmentBytes, prot, flags, &(map.addr), addr);
if (map.addr) {
+ std::lock_guard<std::mutex> guard(mMutexMappings);
mMappings.push_back(map);
}
return err;
@@ -217,22 +218,26 @@
ALOGD("tried to unmap unmapped buffer");
return C2_NOT_FOUND;
}
- for (auto it = mMappings.begin(); it != mMappings.end(); ++it) {
- if (addr != (uint8_t *)it->addr + it->alignmentBytes ||
- size + it->alignmentBytes != it->size) {
- continue;
+ { // Scope for the lock_guard of mMutexMappings.
+ std::lock_guard<std::mutex> guard(mMutexMappings);
+ for (auto it = mMappings.begin(); it != mMappings.end(); ++it) {
+ if (addr != (uint8_t *)it->addr + it->alignmentBytes ||
+ size + it->alignmentBytes != it->size) {
+ continue;
+ }
+ int err = munmap(it->addr, it->size);
+ if (err != 0) {
+ ALOGD("munmap failed");
+ return c2_map_errno<EINVAL>(errno);
+ }
+ if (fence) {
+ *fence = C2Fence(); // not using fences
+ }
+ (void)mMappings.erase(it);
+ ALOGV("successfully unmapped: addr=%p size=%zu fd=%d", addr, size,
+ mHandle.bufferFd());
+ return C2_OK;
}
- int err = munmap(it->addr, it->size);
- if (err != 0) {
- ALOGD("munmap failed");
- return c2_map_errno<EINVAL>(errno);
- }
- if (fence) {
- *fence = C2Fence(); // not using fences
- }
- (void)mMappings.erase(it);
- ALOGV("successfully unmapped: addr=%p size=%zu fd=%d", addr, size, mHandle.bufferFd());
- return C2_OK;
}
ALOGD("unmap failed to find specified map");
return C2_BAD_VALUE;
@@ -241,6 +246,7 @@
virtual ~Impl() {
if (!mMappings.empty()) {
ALOGD("Dangling mappings!");
+ std::lock_guard<std::mutex> guard(mMutexMappings);
for (const Mapping &map : mMappings) {
(void)munmap(map.addr, map.size);
}
@@ -320,6 +326,7 @@
size_t size;
};
std::list<Mapping> mMappings;
+ std::mutex mMutexMappings;
};
class C2AllocationIon::ImplV2 : public C2AllocationIon::Impl {
diff --git a/media/codec2/vndk/C2Store.cpp b/media/codec2/vndk/C2Store.cpp
index 1660c38..dfdd84d 100644
--- a/media/codec2/vndk/C2Store.cpp
+++ b/media/codec2/vndk/C2Store.cpp
@@ -301,13 +301,21 @@
std::lock_guard<std::mutex> lock(_mComponentStoreReadLock);
_mComponentStore = store;
}
- std::shared_ptr<C2AllocatorIon> allocator;
+ std::shared_ptr<C2AllocatorIon> ionAllocator;
{
std::lock_guard<std::mutex> lock(gIonAllocatorMutex);
- allocator = gIonAllocator.lock();
+ ionAllocator = gIonAllocator.lock();
}
- if (allocator) {
- UseComponentStoreForIonAllocator(allocator, store);
+ if (ionAllocator) {
+ UseComponentStoreForIonAllocator(ionAllocator, store);
+ }
+ std::shared_ptr<C2DmaBufAllocator> dmaAllocator;
+ {
+ std::lock_guard<std::mutex> lock(gDmaBufAllocatorMutex);
+ dmaAllocator = gDmaBufAllocator.lock();
+ }
+ if (dmaAllocator) {
+ UseComponentStoreForDmaBufAllocator(dmaAllocator, store);
}
}
diff --git a/media/extractors/flac/Android.bp b/media/extractors/flac/Android.bp
index fd51622..834f4ad 100644
--- a/media/extractors/flac/Android.bp
+++ b/media/extractors/flac/Android.bp
@@ -19,7 +19,7 @@
cc_library {
name: "libflacextractor",
- defaults: ["extractor-defaults", "libbinder_ndk_host_user"],
+ defaults: ["extractor-defaults"],
srcs: ["FLACExtractor.cpp"],
diff --git a/media/extractors/mpeg2/MPEG2PSExtractor.cpp b/media/extractors/mpeg2/MPEG2PSExtractor.cpp
index d431b05..afd28ef 100644
--- a/media/extractors/mpeg2/MPEG2PSExtractor.cpp
+++ b/media/extractors/mpeg2/MPEG2PSExtractor.cpp
@@ -20,9 +20,6 @@
#include "MPEG2PSExtractor.h"
-#include <AnotherPacketSource.h>
-#include <ESQueue.h>
-
#include <media/stagefright/foundation/ABitReader.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -33,6 +30,8 @@
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
+#include <mpeg2ts/AnotherPacketSource.h>
+#include <mpeg2ts/ESQueue.h>
#include <utils/String8.h>
#include <inttypes.h>
diff --git a/media/extractors/mpeg2/MPEG2TSExtractor.cpp b/media/extractors/mpeg2/MPEG2TSExtractor.cpp
index 2e68809..9a3cd92 100644
--- a/media/extractors/mpeg2/MPEG2TSExtractor.cpp
+++ b/media/extractors/mpeg2/MPEG2TSExtractor.cpp
@@ -35,10 +35,9 @@
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
+#include <mpeg2ts/AnotherPacketSource.h>
#include <utils/String8.h>
-#include <AnotherPacketSource.h>
-
#include <hidl/HybridInterface.h>
#include <android/hardware/cas/1.0/ICas.h>
diff --git a/media/extractors/mpeg2/include/MPEG2TSExtractor.h b/media/extractors/mpeg2/include/MPEG2TSExtractor.h
index fd77b08..0e3e484 100644
--- a/media/extractors/mpeg2/include/MPEG2TSExtractor.h
+++ b/media/extractors/mpeg2/include/MPEG2TSExtractor.h
@@ -23,12 +23,11 @@
#include <media/MediaExtractorPluginApi.h>
#include <media/MediaExtractorPluginHelper.h>
#include <media/stagefright/MetaDataBase.h>
+#include <mpeg2ts/ATSParser.h>
#include <utils/threads.h>
#include <utils/KeyedVector.h>
#include <utils/Vector.h>
-#include <ATSParser.h>
-
namespace android {
struct AMessage;
diff --git a/media/extractors/wav/Android.bp b/media/extractors/wav/Android.bp
index b7e2af3..cdf587c 100644
--- a/media/extractors/wav/Android.bp
+++ b/media/extractors/wav/Android.bp
@@ -18,7 +18,7 @@
cc_library {
name: "libwavextractor",
- defaults: ["extractor-defaults", "libbinder_ndk_host_user"],
+ defaults: ["extractor-defaults"],
srcs: ["WAVExtractor.cpp"],
diff --git a/media/janitors/reliability_mainline_OWNERS b/media/janitors/reliability_mainline_OWNERS
index e4c4fc2..cced19c 100644
--- a/media/janitors/reliability_mainline_OWNERS
+++ b/media/janitors/reliability_mainline_OWNERS
@@ -1,5 +1,5 @@
# Bug component: 1051309
-# go/android-media-relaibility
+# go/android-media-reliability
essick@google.com
nchalko@google.com
diff --git a/media/libaaudio/examples/utils/AAudioSimplePlayer.h b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
index 7daac20..956b3cd 100644
--- a/media/libaaudio/examples/utils/AAudioSimplePlayer.h
+++ b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
@@ -40,6 +40,31 @@
int64_t nanoseconds;
} Timestamp;
+static constexpr int32_t kWorkloadScaler = 500;
+
+// Linear congruential random number generator.
+static uint32_t s_random16() {
+ static uint32_t seed = 1234;
+ seed = ((seed * 31421) + 6927) & 0x0FFFF;
+ return seed;
+}
+
+/**
+ * The random number generator is good for burning CPU because the compiler cannot
+ * easily optimize away the computation.
+ * @param workload number of times to execute the loop
+ * @return a white noise value between -1.0 and +1.0
+ */
+static float s_burnCPU(int32_t workload) {
+ uint32_t random = 0;
+ for (int32_t i = 0; i < workload; i++) {
+ for (int32_t j = 0; j < 10; j++) {
+ random = random ^ s_random16();
+ }
+ }
+ return (random - 32768) * (1.0 / 32768);
+}
+
/**
* Simple wrapper for AAudio that opens an output stream either in callback or blocking write mode.
*/
@@ -268,11 +293,13 @@
int32_t timestampCount = 0; // in timestamps
int32_t sampleRate = 48000;
int32_t prefixToneFrames = 0;
+ double workload = 0.0;
bool sweepSetup = false;
int scheduler = 0;
bool schedulerChecked = false;
int32_t hangTimeMSec = 0;
+ int cpuAffinity = -1;
AAudioSimplePlayer simplePlayer;
int32_t callbackCount = 0;
@@ -304,6 +331,14 @@
} SineThreadedData_t;
+int setCpuAffinity(int cpuIndex) {
+cpu_set_t cpu_set;
+ CPU_ZERO(&cpu_set);
+ CPU_SET(cpuIndex, &cpu_set);
+ int err = sched_setaffinity((pid_t) 0, sizeof(cpu_set_t), &cpu_set);
+ return err == 0 ? 0 : -errno;
+}
+
// Callback function that fills the audio output buffer.
aaudio_data_callback_result_t SimplePlayerDataCallbackProc(
AAudioStream *stream,
@@ -319,6 +354,10 @@
}
SineThreadedData_t *sineData = (SineThreadedData_t *) userData;
+ if (sineData->cpuAffinity >= 0) {
+ setCpuAffinity(sineData->cpuAffinity);
+ sineData->cpuAffinity = -1;
+ }
// Play an initial high tone so we can tell whether the beginning was truncated.
if (!sineData->sweepSetup && sineData->framesTotal >= sineData->prefixToneFrames) {
sineData->setupSineSweeps();
@@ -398,6 +437,8 @@
return AAUDIO_CALLBACK_RESULT_STOP;
}
+ s_burnCPU((int32_t)(sineData->workload * kWorkloadScaler * numFrames));
+
sineData->callbackCount++;
sineData->framesTotal += numFrames;
return AAUDIO_CALLBACK_RESULT_CONTINUE;
diff --git a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
index cdc987b..400fc7c 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
@@ -31,10 +31,10 @@
#include "AAudioSimplePlayer.h"
#include "AAudioArgsParser.h"
-#define APP_VERSION "0.1.8"
+#define APP_VERSION "0.2.1"
-constexpr int32_t kDefaultHangTimeMSec = 10;
-
+static constexpr int32_t kDefaultHangTimeMSec = 10;
+static constexpr int32_t kWorkPeriodSeconds = 6;
/**
* Open stream, play some sine waves, then close the stream.
*
@@ -44,7 +44,11 @@
static aaudio_result_t testOpenPlayClose(AAudioArgsParser &argParser,
int32_t loopCount,
int32_t prefixToneMsec,
- int32_t hangTimeMSec)
+ int32_t hangTimeMSec,
+ int cpuAffinity,
+ double lowWorkLoad,
+ double highWorkLoad,
+ int32_t workPeriodSeconds)
{
SineThreadedData_t myData;
AAudioSimplePlayer &player = myData.simplePlayer;
@@ -57,6 +61,7 @@
myData.schedulerChecked = false;
myData.callbackCount = 0;
myData.hangTimeMSec = hangTimeMSec; // test AAudioStream_getXRunCount()
+ myData.cpuAffinity = cpuAffinity;
result = player.open(argParser,
SimplePlayerDataCallbackProc,
@@ -111,8 +116,8 @@
}
// Play a sine wave in the background.
- printf("Sleep for %d seconds while audio plays in a callback thread. %d of %d\n",
- argParser.getDurationSeconds(), (loopIndex + 1), loopCount);
+ printf("Monitor for %d seconds while audio plays in a callback thread. %d of %d, %d\n",
+ argParser.getDurationSeconds(), (loopIndex + 1), loopCount, workPeriodSeconds);
startedAtNanos = getNanoseconds(CLOCK_MONOTONIC);
for (int second = 0; second < durationSeconds; second++) {
// Sleep a while. Wake up early if there is an error, for example a DISCONNECT.
@@ -123,13 +128,17 @@
const int32_t framesWritten = (int32_t) AAudioStream_getFramesWritten(player.getStream());
const int32_t framesRead = (int32_t) AAudioStream_getFramesRead(player.getStream());
const int32_t xruns = AAudioStream_getXRunCount(player.getStream());
+ myData.workload = ((second % (2 * workPeriodSeconds)) < workPeriodSeconds)
+ ? lowWorkLoad : highWorkLoad;
printf(" waker result = %d, at %6d millis"
- ", second = %3d, frames written %8d - read %8d = %8d, underruns = %d\n",
+ ", second = %3d, frames written %8d - read %8d = %8d"
+ ", work = %5.1f, underruns = %d\n",
result, (int) millis,
second,
framesWritten,
framesRead,
framesWritten - framesRead,
+ myData.workload,
xruns);
if (result != AAUDIO_OK) {
disconnected = (result == AAUDIO_ERROR_DISCONNECTED);
@@ -220,6 +229,11 @@
AAudioArgsParser::usage();
printf(" -l{count} loopCount start/stop, every other one is silent\n");
printf(" -t{msec} play a high pitched tone at the beginning\n");
+ printf(" -w{workload} set base workload, default 0.0\n");
+ printf(" -W{workload} alternate between this higher workload and base workload\n");
+ printf(" -Z{duration} number of seconds to spend at each workload, default = %d\n",
+ kWorkPeriodSeconds);
+ printf(" -a{cpu} set CPU affinity, default none\n");
printf(" -h{msec} force periodic underruns by hanging in callback\n");
printf(" If no value specified then %d used.\n",
kDefaultHangTimeMSec);
@@ -232,6 +246,10 @@
int32_t loopCount = 1;
int32_t prefixToneMsec = 0;
int32_t hangTimeMSec = 0;
+ int cpuAffinity = -1;
+ double lowWorkLoad = 0.0;
+ double highWorkLoad = -1.0;
+ int32_t workPeriodSeconds = kWorkPeriodSeconds;
// Make printf print immediately so that debug info is not stuck
// in a buffer if we hang or crash.
@@ -247,6 +265,9 @@
if (arg[0] == '-') {
char option = arg[1];
switch (option) {
+ case 'a':
+ cpuAffinity = atoi(&arg[2]);
+ break;
case 'l':
loopCount = atoi(&arg[2]);
break;
@@ -258,6 +279,15 @@
? atoi(&arg[2])
: kDefaultHangTimeMSec;
break;
+ case 'w':
+ lowWorkLoad = atof(&arg[2]);
+ break;
+ case 'W':
+ highWorkLoad = atof(&arg[2]);
+ break;
+ case 'Z':
+ workPeriodSeconds = atoi(&arg[2]);
+ break;
default:
usage();
exit(EXIT_FAILURE);
@@ -271,9 +301,21 @@
}
}
+ if (highWorkLoad > 0) {
+ if (highWorkLoad < lowWorkLoad) {
+ printf("ERROR - -W%f workload lower than -w%f workload", highWorkLoad, lowWorkLoad);
+ return EXIT_FAILURE;
+ }
+ } else {
+ highWorkLoad = lowWorkLoad; // high not specified so use low
+ }
+
// Keep looping until we can complete the test without disconnecting.
while((result = testOpenPlayClose(argParser, loopCount,
- prefixToneMsec, hangTimeMSec))
+ prefixToneMsec, hangTimeMSec,
+ cpuAffinity,
+ lowWorkLoad, highWorkLoad,
+ workPeriodSeconds))
== AAUDIO_ERROR_DISCONNECTED);
return (result) ? EXIT_FAILURE : EXIT_SUCCESS;
diff --git a/media/libaaudio/include/aaudio/AAudioTesting.h b/media/libaaudio/include/aaudio/AAudioTesting.h
index 02ec411..0f2d7a2 100644
--- a/media/libaaudio/include/aaudio/AAudioTesting.h
+++ b/media/libaaudio/include/aaudio/AAudioTesting.h
@@ -49,6 +49,12 @@
};
typedef int32_t aaudio_policy_t;
+// Internal error codes. Only used by the framework.
+enum {
+ AAUDIO_INTERNAL_ERROR_BASE = -1000,
+ AAUDIO_ERROR_STANDBY,
+};
+
/**
* Control whether AAudioStreamBuilder_openStream() will use the new MMAP data path
* or the older "Legacy" data path.
diff --git a/media/libaaudio/scripts/measure_device_power.py b/media/libaaudio/scripts/measure_device_power.py
new file mode 100755
index 0000000..9603f88
--- /dev/null
+++ b/media/libaaudio/scripts/measure_device_power.py
@@ -0,0 +1,272 @@
+#!/usr/bin/python3
+"""
+ * 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.
+"""
+
+'''
+Measure CPU related power on Pixel 6 or later devices using ODPM,
+the On Device Power Measurement tool.
+Generate a CSV report for putting in a spreadsheet
+'''
+
+import argparse
+import os
+import re
+import subprocess
+import sys
+import time
+
+# defaults
+PRE_DELAY_SECONDS = 0.5 # time to sleep before command to avoid adb unroot error
+DEFAULT_NUM_ITERATIONS = 5
+DEFAULT_FILE_NAME = 'energy_commands.txt'
+
+'''
+Default rail assignments
+philburk-macbookpro3:expt philburk$ adb shell cat /sys/bus/iio/devices/iio\:device0/energy_value
+t=349894
+CH0(T=349894)[S10M_VDD_TPU], 5578756
+CH1(T=349894)[VSYS_PWR_MODEM], 29110940
+CH2(T=349894)[VSYS_PWR_RFFE], 3166046
+CH3(T=349894)[S2M_VDD_CPUCL2], 30203502
+CH4(T=349894)[S3M_VDD_CPUCL1], 23377533
+CH5(T=349894)[S4M_VDD_CPUCL0], 46356942
+CH6(T=349894)[S5M_VDD_INT], 10771876
+CH7(T=349894)[S1M_VDD_MIF], 21091363
+philburk-macbookpro3:expt philburk$ adb shell cat /sys/bus/iio/devices/iio\:device1/energy_value
+t=359458
+CH0(T=359458)[VSYS_PWR_WLAN_BT], 45993209
+CH1(T=359458)[L2S_VDD_AOC_RET], 2822928
+CH2(T=359458)[S9S_VDD_AOC], 6923706
+CH3(T=359458)[S5S_VDDQ_MEM], 4658202
+CH4(T=359458)[S10S_VDD2L], 5506273
+CH5(T=359458)[S4S_VDD2H_MEM], 14254574
+CH6(T=359458)[S2S_VDD_G3D], 5315420
+CH7(T=359458)[VSYS_PWR_DISPLAY], 81221665
+'''
+
+'''
+LDO2M(L2M_ALIVE):DDR -> DRAM Array Core Power
+BUCK4S(S4S_VDD2H_MEM):DDR -> Normal operation data and control path logic circuits
+BUCK5S(S5S_VDDQ_MEM):DDR -> LPDDR I/O interface
+BUCK10S(S10S_VDD2L):DDR -> DVFSC (1600Mbps or lower) operation data and control path logic circuits
+BUCK1M (S1M_VDD_MIF): SoC side Memory InterFace and Controller
+'''
+
+# Map between rail name and human readable name.
+ENERGY_DICTIONARY = { \
+ 'S4M_VDD_CPUCL0': 'CPU0', \
+ 'S3M_VDD_CPUCL1': 'CPU1', \
+ 'S2M_VDD_CPUCL2': 'CPU2', \
+ 'S1M_VDD_MIF': 'MIF', \
+ 'L2M_ALIVE': 'DDRAC', \
+ 'S4S_VDD2H_MEM': 'DDRNO', \
+ 'S10S_VDD2L': 'DDR16', \
+ 'S5S_VDDQ_MEM': 'DDRIO', \
+ 'VSYS_PWR_DISPLAY': 'SCREEN'}
+
+SORTED_ENERGY_LIST = sorted(ENERGY_DICTIONARY, key=ENERGY_DICTIONARY.get)
+
+# Sometimes "adb unroot" returns 1!
+# So try several times.
+# @return 0 on success
+def adbUnroot():
+ returnCode = 1
+ count = 0
+ limit = 5
+ while count < limit and returnCode != 0:
+ print(('Try to adb unroot {} of {}'.format(count, limit)))
+ subprocess.call(["adb", "wait-for-device"])
+ time.sleep(PRE_DELAY_SECONDS)
+ returnCode = subprocess.call(["adb", "unroot"])
+ print(('returnCode = {}'.format(returnCode)))
+ count += 1
+ return returnCode
+
+# @param commandString String containing shell command
+# @return Both the stdout and stderr of the commands run
+def runCommand(commandString):
+ print(commandString)
+ if commandString == "adb unroot":
+ result = adbUnroot()
+ else:
+ commandArray = commandString.split(' ')
+ result = subprocess.run(commandArray, check=True, capture_output=True).stdout
+ return result
+
+# @param commandString String containing ADB command
+# @return Both the stdout and stderr of the commands run
+def adbCommand(commandString):
+ if commandString == "unroot":
+ result = adbUnroot()
+ else:
+ print(("adb " + commandString))
+ commandArray = ["adb"] + commandString.split(' ')
+ subprocess.call(["adb", "wait-for-device"])
+ result = subprocess.run(commandArray, check=True, capture_output=True).stdout
+ return result
+
+# Parse a line that looks like "CH3(T=10697635)[S2M_VDD_CPUCL2], 116655335"
+# Use S2M_VDD_CPUCL2 as the tag and set value to the number
+# in the report dictionary.
+def parseEnergyValue(string):
+ return tuple(re.split('\[|\], +', string)[1:])
+
+# Read accumulated energy into a dictionary.
+def measureEnergyForDevice(deviceIndex, report):
+ # print("measureEnergyForDevice " + str(deviceIndex))
+ tableBytes = adbCommand( \
+ 'shell cat /sys/bus/iio/devices/iio\:device{}/energy_value'\
+ .format(deviceIndex))
+ table = tableBytes.decode("utf-8")
+ # print(table)
+ for count, line in enumerate(table.splitlines()):
+ if count > 0:
+ tagEnergy = parseEnergyValue(line)
+ report[tagEnergy[0]] = int(tagEnergy[1].strip())
+ # print(report)
+
+def measureEnergyOnce():
+ adbCommand("root")
+ report = {}
+ d0 = measureEnergyForDevice(0, report)
+ d1 = measureEnergyForDevice(1, report)
+ adbUnroot()
+ return report
+
+# Subtract numeric values for matching keys.
+def subtractReports(A, B):
+ return {x: A[x] - B[x] for x in A if x in B}
+
+# Add numeric values for matching keys.
+def addReports(A, B):
+ return {x: A[x] + B[x] for x in A if x in B}
+
+# Divide numeric values by divisor.
+# @return Modified copy of report.
+def divideReport(report, divisor):
+ return {key: val / divisor for key, val in list(report.items())}
+
+# Generate a dictionary that is the difference between two measurements over time.
+def measureEnergyOverTime(duration):
+ report1 = measureEnergyOnce()
+ print(("Measure energy for " + str(duration) + " seconds."))
+ time.sleep(duration)
+ report2 = measureEnergyOnce()
+ return subtractReports(report2, report1)
+
+# Generate a CSV string containing the human readable headers.
+def formatEnergyHeader():
+ header = ""
+ for tag in SORTED_ENERGY_LIST:
+ header += ENERGY_DICTIONARY[tag] + ", "
+ return header
+
+# Generate a CSV string containing the numeric values.
+def formatEnergyData(report):
+ data = ""
+ for tag in SORTED_ENERGY_LIST:
+ if tag in list(report.keys()):
+ data += str(report[tag]) + ", "
+ else:
+ data += "-1,"
+ return data
+
+def printEnergyReport(report):
+ s = "\n"
+ s += "Values are in microWattSeconds\n"
+ s += "Report below is CSV format for pasting into a spreadsheet:\n"
+ s += formatEnergyHeader() + "\n"
+ s += formatEnergyData(report) + "\n"
+ print(s)
+
+# Generate a dictionary that is the difference between two measurements
+# before and after executing the command.
+def measureEnergyForCommand(command):
+ report1 = measureEnergyOnce()
+ print(("Measure energy for: " + command))
+ result = runCommand(command)
+ report2 = measureEnergyOnce()
+ # print(result)
+ return subtractReports(report2, report1)
+
+# Average the results of several measurements for one command.
+def averageEnergyForCommand(command, count):
+ print("=================== #0\n")
+ sumReport = measureEnergyForCommand(command)
+ for i in range(1, count):
+ print(("=================== #" + str(i) + "\n"))
+ report = measureEnergyForCommand(command)
+ sumReport = addReports(sumReport, report)
+ print(sumReport)
+ return divideReport(sumReport, count)
+
+# Parse a list of commands in a file.
+# Lines ending in "\" are continuation lines.
+# Lines beginning with "#" are comments.
+def measureEnergyForCommands(fileName):
+ finalReport = "------------------------------------\n"
+ finalReport += "comment, command, " + formatEnergyHeader() + "\n"
+ comment = ""
+ try:
+ fp = open(fileName)
+ line = fp.readline()
+ while line:
+ command = line.strip()
+ if command.endswith('\\'):
+ command = command[:-1].strip() # remove \\:
+ runCommand(command)
+ elif command.startswith("#"):
+ # ignore comment
+ print((command + "\n"))
+ comment = command
+ elif command:
+ report = averageEnergyForCommand(command, DEFAULT_NUM_ITERATIONS)
+ finalReport += comment + ", " + command + ", " + formatEnergyData(report) + "\n"
+ print(finalReport)
+ line = fp.readline()
+ finally:
+ fp.close()
+ return finalReport
+
+def main():
+ # parse command line args
+ parser = argparse.ArgumentParser()
+ parser.add_argument('-s', '--seconds',
+ help="Measure power for N seconds. Ignore scriptFile.",
+ type=float)
+ parser.add_argument("fileName",
+ nargs = '?',
+ help="Path to file containing commands to be measured."
+ + " Default path = " + DEFAULT_FILE_NAME + "."
+ + " Lines ending in '\' are continuation lines."
+ + " Lines beginning with '#' are comments.",
+ default=DEFAULT_FILE_NAME)
+ args=parser.parse_args();
+
+ print(("seconds = " + str(args.seconds)))
+ print(("fileName = " + str(args.fileName)))
+ # Process command line
+ if args.seconds:
+ report = measureEnergyOverTime(args.seconds)
+ printEnergyReport(report)
+ else:
+ report = measureEnergyForCommands(args.fileName)
+ print(report)
+ print("Finished.\n")
+ return 0
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/media/libaaudio/scripts/setup_odpm_cpu_rails.sh b/media/libaaudio/scripts/setup_odpm_cpu_rails.sh
new file mode 100755
index 0000000..e9241b9
--- /dev/null
+++ b/media/libaaudio/scripts/setup_odpm_cpu_rails.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+# Configure ODPM rails to measure CPU specific power.
+# See go/odpm-p21-userguide
+
+adb root
+
+# LDO2M(L2M_ALIVE) - DRAM Array Core Power
+adb shell 'echo "CH0=LDO2M" > /sys/bus/iio/devices/iio\:device0/enabled_rails'
+
+# These are the defaults.
+# BUCK2M(S2M_VDD_CPUCL2):CPU(BIG)
+# adb shell 'echo "CH3=BUCK2M" > /sys/bus/iio/devices/iio\:device0/enabled_rails'
+# BUCK3M(S3M_VDD_CPUCL1):CPU(MID)
+# adb shell 'echo "CH4=BUCK3M" > /sys/bus/iio/devices/iio\:device0/enabled_rails'
+# BUCK4M(S4M_VDD_CPUCL0):CPU(LITTLE)
+# adb shell 'echo "CH5=BUCK4M" > /sys/bus/iio/devices/iio\:device0/enabled_rails'
+# BUCK1M(S1M_VDD_MIF):MIF
+# adb shell 'echo "CH7=BUCK1M" > /sys/bus/iio/devices/iio\:device0/enabled_rails'
+
+# These are default on device1.
+# BUCK5S(S5S_VDDQ_MEM):DDR
+# adb shell 'echo "CH3=BUCK5S" > /sys/bus/iio/devices/iio\:device1/enabled_rails'
+# BUCK10S(S10S_VDD2L):DDR
+# adb shell 'echo "CH4=BUCK10S" > /sys/bus/iio/devices/iio\:device1/enabled_rails'
+# BUCK4S(S4S_VDD2H_MEM):DDR
+# adb shell 'echo "CH5=BUCK4S" > /sys/bus/iio/devices/iio\:device1/enabled_rails'
+
+adb shell 'cat /sys/bus/iio/devices/iio\:device0/enabled_rails'
+adb shell 'cat /sys/bus/iio/devices/iio\:device1/enabled_rails'
+
+adb unroot
+
diff --git a/media/libaaudio/src/Android.bp b/media/libaaudio/src/Android.bp
index 38bcb7c..f50b53a 100644
--- a/media/libaaudio/src/Android.bp
+++ b/media/libaaudio/src/Android.bp
@@ -214,6 +214,7 @@
"flowgraph/MonoBlend.cpp",
"flowgraph/MonoToMultiConverter.cpp",
"flowgraph/MultiToMonoConverter.cpp",
+ "flowgraph/MultiToManyConverter.cpp",
"flowgraph/RampLinear.cpp",
"flowgraph/SampleRateConverter.cpp",
"flowgraph/SinkFloat.cpp",
diff --git a/media/libaaudio/src/binding/AAudioBinderAdapter.cpp b/media/libaaudio/src/binding/AAudioBinderAdapter.cpp
index 6e3a1c8..42d81ca 100644
--- a/media/libaaudio/src/binding/AAudioBinderAdapter.cpp
+++ b/media/libaaudio/src/binding/AAudioBinderAdapter.cpp
@@ -124,4 +124,16 @@
return result;
}
+aaudio_result_t AAudioBinderAdapter::exitStandby(aaudio_handle_t streamHandle,
+ AudioEndpointParcelable &endpointOut) {
+ aaudio_result_t result;
+ Endpoint endpoint;
+ Status status = mDelegate->exitStandby(streamHandle, &endpoint, &result);
+ if (!status.isOk()) {
+ result = AAudioConvert_androidToAAudioResult(statusTFromBinderStatus(status));
+ }
+ endpointOut = std::move(endpoint);
+ return result;
+}
+
} // namespace aaudio
diff --git a/media/libaaudio/src/binding/AAudioBinderAdapter.h b/media/libaaudio/src/binding/AAudioBinderAdapter.h
index 5e9ab57..d170783 100644
--- a/media/libaaudio/src/binding/AAudioBinderAdapter.h
+++ b/media/libaaudio/src/binding/AAudioBinderAdapter.h
@@ -57,6 +57,9 @@
aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
pid_t clientThreadId) override;
+ aaudio_result_t exitStandby(aaudio_handle_t streamHandle,
+ AudioEndpointParcelable &parcelable) override;
+
private:
IAAudioService* const mDelegate;
};
diff --git a/media/libaaudio/src/binding/AAudioBinderClient.cpp b/media/libaaudio/src/binding/AAudioBinderClient.cpp
index 135bac3..8e5facc 100644
--- a/media/libaaudio/src/binding/AAudioBinderClient.cpp
+++ b/media/libaaudio/src/binding/AAudioBinderClient.cpp
@@ -201,3 +201,11 @@
return service->unregisterAudioThread(streamHandle, clientThreadId);
}
+
+aaudio_result_t AAudioBinderClient::exitStandby(aaudio_handle_t streamHandle,
+ AudioEndpointParcelable &endpointOut) {
+ std::shared_ptr<AAudioServiceInterface> service = getAAudioService();
+ if (service.get() == nullptr) return AAUDIO_ERROR_NO_SERVICE;
+
+ return service->exitStandby(streamHandle, endpointOut);
+}
diff --git a/media/libaaudio/src/binding/AAudioBinderClient.h b/media/libaaudio/src/binding/AAudioBinderClient.h
index 557ced5..0968f4c 100644
--- a/media/libaaudio/src/binding/AAudioBinderClient.h
+++ b/media/libaaudio/src/binding/AAudioBinderClient.h
@@ -108,6 +108,9 @@
return AAUDIO_ERROR_UNAVAILABLE;
}
+ aaudio_result_t exitStandby(aaudio_handle_t streamHandle,
+ AudioEndpointParcelable &endpointOut) override;
+
void onStreamChange(aaudio_handle_t /*handle*/, int32_t /*opcode*/, int32_t /*value*/) {
// TODO This is just a stub so we can have a client Binder to pass to the service.
// TODO Implemented in a later CL.
diff --git a/media/libaaudio/src/binding/AAudioServiceInterface.h b/media/libaaudio/src/binding/AAudioServiceInterface.h
index bf94774..e901767 100644
--- a/media/libaaudio/src/binding/AAudioServiceInterface.h
+++ b/media/libaaudio/src/binding/AAudioServiceInterface.h
@@ -95,6 +95,16 @@
virtual aaudio_result_t stopClient(aaudio_handle_t streamHandle,
audio_port_handle_t clientHandle) = 0;
+
+ /**
+ * Exit the standby mode.
+ *
+ * @param streamHandle the stream handle
+ * @param parcelable contains new data queue information
+ * @return the result of the execution
+ */
+ virtual aaudio_result_t exitStandby(aaudio_handle_t streamHandle,
+ AudioEndpointParcelable &parcelable) = 0;
};
} /* namespace aaudio */
diff --git a/media/libaaudio/src/binding/AudioEndpointParcelable.cpp b/media/libaaudio/src/binding/AudioEndpointParcelable.cpp
index dea3e4a..b1262df 100644
--- a/media/libaaudio/src/binding/AudioEndpointParcelable.cpp
+++ b/media/libaaudio/src/binding/AudioEndpointParcelable.cpp
@@ -79,6 +79,22 @@
return index;
}
+void AudioEndpointParcelable::closeDataFileDescriptor() {
+ const int32_t curDataMemoryIndex = mDownDataQueueParcelable.getSharedMemoryIndex();
+ mSharedMemories[curDataMemoryIndex].closeAndReleaseFd();
+}
+
+void AudioEndpointParcelable::updateDataFileDescriptor(
+ AudioEndpointParcelable* endpointParcelable) {
+ const int32_t curDataMemoryIndex = mDownDataQueueParcelable.getSharedMemoryIndex();
+ const int32_t newDataMemoryIndex =
+ endpointParcelable->mDownDataQueueParcelable.getSharedMemoryIndex();
+ mSharedMemories[curDataMemoryIndex].close();
+ mSharedMemories[curDataMemoryIndex].setup(
+ endpointParcelable->mSharedMemories[newDataMemoryIndex]);
+ mDownDataQueueParcelable.updateMemory(endpointParcelable->mDownDataQueueParcelable);
+}
+
aaudio_result_t AudioEndpointParcelable::resolve(EndpointDescriptor *descriptor) {
aaudio_result_t result = mUpMessageQueueParcelable.resolve(mSharedMemories,
&descriptor->upMessageQueueDescriptor);
@@ -92,6 +108,10 @@
return result;
}
+aaudio_result_t AudioEndpointParcelable::resolveDataQueue(RingBufferDescriptor *descriptor) {
+ return mDownDataQueueParcelable.resolve(mSharedMemories, descriptor);
+}
+
aaudio_result_t AudioEndpointParcelable::close() {
int err = 0;
for (int i = 0; i < mNumSharedMemories; i++) {
diff --git a/media/libaaudio/src/binding/AudioEndpointParcelable.h b/media/libaaudio/src/binding/AudioEndpointParcelable.h
index 544aa92..5d2c38f 100644
--- a/media/libaaudio/src/binding/AudioEndpointParcelable.h
+++ b/media/libaaudio/src/binding/AudioEndpointParcelable.h
@@ -52,7 +52,20 @@
*/
int32_t addFileDescriptor(const android::base::unique_fd& fd, int32_t sizeInBytes);
+ /**
+ * Close current data file descriptor. The duplicated file descriptor will be close.
+ */
+ void closeDataFileDescriptor();
+
+ /**
+ * Update current data file descriptor with given endpoint parcelable.
+ * @param endpointParcelable an endpoint parcelable that contains new data file
+ * descriptor information
+ */
+ void updateDataFileDescriptor(AudioEndpointParcelable* endpointParcelable);
+
aaudio_result_t resolve(EndpointDescriptor *descriptor);
+ aaudio_result_t resolveDataQueue(RingBufferDescriptor *descriptor);
aaudio_result_t close();
diff --git a/media/libaaudio/src/binding/RingBufferParcelable.cpp b/media/libaaudio/src/binding/RingBufferParcelable.cpp
index fa7ca72..3bc51d0 100644
--- a/media/libaaudio/src/binding/RingBufferParcelable.cpp
+++ b/media/libaaudio/src/binding/RingBufferParcelable.cpp
@@ -33,6 +33,7 @@
: mReadCounterParcelable(parcelable.readCounterParcelable),
mWriteCounterParcelable(parcelable.writeCounterParcelable),
mDataParcelable(parcelable.dataParcelable),
+ mSharedMemoryIndex(parcelable.sharedMemoryIndex),
mBytesPerFrame(parcelable.bytesPerFrame),
mFramesPerBurst(parcelable.framesPerBurst),
mCapacityInFrames(parcelable.capacityInFrames),
@@ -45,6 +46,7 @@
result.readCounterParcelable = mReadCounterParcelable.parcelable();
result.writeCounterParcelable = mWriteCounterParcelable.parcelable();
result.dataParcelable = mDataParcelable.parcelable();
+ result.sharedMemoryIndex = mSharedMemoryIndex;
result.bytesPerFrame = mBytesPerFrame;
result.framesPerBurst = mFramesPerBurst;
result.capacityInFrames = mCapacityInFrames;
@@ -60,6 +62,7 @@
int32_t readCounterOffset,
int32_t writeCounterOffset,
int32_t counterSizeBytes) {
+ mSharedMemoryIndex = sharedMemoryIndex;
mReadCounterParcelable.setup(sharedMemoryIndex, readCounterOffset, counterSizeBytes);
mWriteCounterParcelable.setup(sharedMemoryIndex, writeCounterOffset, counterSizeBytes);
mDataParcelable.setup(sharedMemoryIndex, dataMemoryOffset, dataSizeInBytes);
@@ -68,12 +71,13 @@
void RingBufferParcelable::setupMemory(int32_t sharedMemoryIndex,
int32_t dataMemoryOffset,
int32_t dataSizeInBytes) {
+ mSharedMemoryIndex = sharedMemoryIndex;
mReadCounterParcelable.setup(sharedMemoryIndex, 0, 0);
mWriteCounterParcelable.setup(sharedMemoryIndex, 0, 0);
mDataParcelable.setup(sharedMemoryIndex, dataMemoryOffset, dataSizeInBytes);
}
-int32_t RingBufferParcelable::getBytesPerFrame() {
+int32_t RingBufferParcelable::getBytesPerFrame() const {
return mBytesPerFrame;
}
@@ -81,7 +85,7 @@
mBytesPerFrame = bytesPerFrame;
}
-int32_t RingBufferParcelable::getFramesPerBurst() {
+int32_t RingBufferParcelable::getFramesPerBurst() const {
return mFramesPerBurst;
}
@@ -89,7 +93,7 @@
mFramesPerBurst = framesPerBurst;
}
-int32_t RingBufferParcelable::getCapacityInFrames() {
+int32_t RingBufferParcelable::getCapacityInFrames() const {
return mCapacityInFrames;
}
@@ -124,6 +128,14 @@
return AAUDIO_OK;
}
+void RingBufferParcelable::updateMemory(const RingBufferParcelable& parcelable) {
+ setupMemory(mSharedMemoryIndex, 0,
+ parcelable.getCapacityInFrames() * parcelable.getBytesPerFrame());
+ setBytesPerFrame(parcelable.getBytesPerFrame());
+ setFramesPerBurst(parcelable.getFramesPerBurst());
+ setCapacityInFrames(parcelable.getCapacityInFrames());
+}
+
aaudio_result_t RingBufferParcelable::validate() const {
if (mCapacityInFrames < 0 || mCapacityInFrames >= 32 * 1024) {
ALOGE("invalid mCapacityInFrames = %d", mCapacityInFrames);
diff --git a/media/libaaudio/src/binding/RingBufferParcelable.h b/media/libaaudio/src/binding/RingBufferParcelable.h
index 2508cea..29d0d86 100644
--- a/media/libaaudio/src/binding/RingBufferParcelable.h
+++ b/media/libaaudio/src/binding/RingBufferParcelable.h
@@ -46,15 +46,15 @@
int32_t dataMemoryOffset,
int32_t dataSizeInBytes);
- int32_t getBytesPerFrame();
+ int32_t getBytesPerFrame() const;
void setBytesPerFrame(int32_t bytesPerFrame);
- int32_t getFramesPerBurst();
+ int32_t getFramesPerBurst() const;
void setFramesPerBurst(int32_t framesPerBurst);
- int32_t getCapacityInFrames();
+ int32_t getCapacityInFrames() const;
void setCapacityInFrames(int32_t capacityInFrames);
@@ -62,6 +62,12 @@
aaudio_result_t resolve(SharedMemoryParcelable *memoryParcels, RingBufferDescriptor *descriptor);
+ void updateMemory(const RingBufferParcelable& parcelable);
+
+ int32_t getSharedMemoryIndex() const {
+ return mSharedMemoryIndex;
+ }
+
void dump();
// Extract a parcelable representation of this object.
@@ -71,6 +77,7 @@
SharedRegionParcelable mReadCounterParcelable;
SharedRegionParcelable mWriteCounterParcelable;
SharedRegionParcelable mDataParcelable;
+ int32_t mSharedMemoryIndex = -1;
int32_t mBytesPerFrame = 0; // index is in frames
int32_t mFramesPerBurst = 0; // for ISOCHRONOUS queues
int32_t mCapacityInFrames = 0; // zero if unused
diff --git a/media/libaaudio/src/binding/SharedMemoryParcelable.cpp b/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
index 3a49655..741aefc 100644
--- a/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
+++ b/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
@@ -64,6 +64,10 @@
mSizeInBytes = sizeInBytes;
}
+void SharedMemoryParcelable::setup(const SharedMemoryParcelable &sharedMemoryParcelable) {
+ setup(sharedMemoryParcelable.mFd, sharedMemoryParcelable.mSizeInBytes);
+}
+
aaudio_result_t SharedMemoryParcelable::close() {
if (mResolvedAddress != MMAP_UNRESOLVED_ADDRESS) {
int err = munmap(mResolvedAddress, mSizeInBytes);
@@ -76,6 +80,14 @@
return AAUDIO_OK;
}
+aaudio_result_t SharedMemoryParcelable::closeAndReleaseFd() {
+ aaudio_result_t result = close();
+ if (result == AAUDIO_OK) {
+ mFd.reset();
+ }
+ return result;
+}
+
aaudio_result_t SharedMemoryParcelable::resolveSharedMemory(const unique_fd& fd) {
mResolvedAddress = (uint8_t *) mmap(nullptr, mSizeInBytes, PROT_READ | PROT_WRITE,
MAP_SHARED, fd.get(), 0);
diff --git a/media/libaaudio/src/binding/SharedMemoryParcelable.h b/media/libaaudio/src/binding/SharedMemoryParcelable.h
index 1f2c335..7762fef 100644
--- a/media/libaaudio/src/binding/SharedMemoryParcelable.h
+++ b/media/libaaudio/src/binding/SharedMemoryParcelable.h
@@ -52,12 +52,16 @@
*/
void setup(const android::base::unique_fd& fd, int32_t sizeInBytes);
+ void setup(const SharedMemoryParcelable& sharedMemoryParcelable);
+
// mmap() shared memory
aaudio_result_t resolve(int32_t offsetInBytes, int32_t sizeInBytes, void **regionAddressPtr);
// munmap() any mapped memory
aaudio_result_t close();
+ aaudio_result_t closeAndReleaseFd();
+
int32_t getSizeInBytes();
void dump();
diff --git a/media/libaaudio/src/binding/aidl/aaudio/IAAudioService.aidl b/media/libaaudio/src/binding/aidl/aaudio/IAAudioService.aidl
index 44d2211..485c2e2 100644
--- a/media/libaaudio/src/binding/aidl/aaudio/IAAudioService.aidl
+++ b/media/libaaudio/src/binding/aidl/aaudio/IAAudioService.aidl
@@ -78,4 +78,6 @@
int unregisterAudioThread(int streamHandle,
int clientThreadId);
+
+ int exitStandby(int streamHandle, out Endpoint endpoint);
}
diff --git a/media/libaaudio/src/binding/aidl/aaudio/RingBuffer.aidl b/media/libaaudio/src/binding/aidl/aaudio/RingBuffer.aidl
index a58b33a..dd64493 100644
--- a/media/libaaudio/src/binding/aidl/aaudio/RingBuffer.aidl
+++ b/media/libaaudio/src/binding/aidl/aaudio/RingBuffer.aidl
@@ -26,4 +26,5 @@
int framesPerBurst; // for ISOCHRONOUS queues
int capacityInFrames; // zero if unused
int /* RingbufferFlags */ flags; // = RingbufferFlags::NONE;
+ int sharedMemoryIndex;
}
\ No newline at end of file
diff --git a/media/libaaudio/src/client/AAudioFlowGraph.cpp b/media/libaaudio/src/client/AAudioFlowGraph.cpp
index d3e2912..d0c3238 100644
--- a/media/libaaudio/src/client/AAudioFlowGraph.cpp
+++ b/media/libaaudio/src/client/AAudioFlowGraph.cpp
@@ -21,8 +21,10 @@
#include "AAudioFlowGraph.h"
#include <flowgraph/ClipToRange.h>
+#include <flowgraph/ManyToMultiConverter.h>
#include <flowgraph/MonoBlend.h>
#include <flowgraph/MonoToMultiConverter.h>
+#include <flowgraph/MultiToManyConverter.h>
#include <flowgraph/RampLinear.h>
#include <flowgraph/SinkFloat.h>
#include <flowgraph/SinkI16.h>
@@ -39,12 +41,16 @@
int32_t sourceChannelCount,
audio_format_t sinkFormat,
int32_t sinkChannelCount,
- bool useMonoBlend) {
+ bool useMonoBlend,
+ float audioBalance,
+ bool isExclusive) {
FlowGraphPortFloatOutput *lastOutput = nullptr;
// TODO change back to ALOGD
- ALOGI("%s() source format = 0x%08x, channels = %d, sink format = 0x%08x, channels = %d",
- __func__, sourceFormat, sourceChannelCount, sinkFormat, sinkChannelCount);
+ ALOGI("%s() source format = 0x%08x, channels = %d, sink format = 0x%08x, channels = %d, "
+ "useMonoBlend = %d, audioBalance = %f, isExclusive %d",
+ __func__, sourceFormat, sourceChannelCount, sinkFormat, sinkChannelCount,
+ useMonoBlend, audioBalance, isExclusive);
switch (sourceFormat) {
case AUDIO_FORMAT_PCM_FLOAT:
@@ -65,10 +71,11 @@
}
lastOutput = &mSource->output;
- // Apply volume as a ramp to avoid pops.
- mVolumeRamp = std::make_unique<RampLinear>(sourceChannelCount);
- lastOutput->connect(&mVolumeRamp->input);
- lastOutput = &mVolumeRamp->output;
+ if (useMonoBlend) {
+ mMonoBlend = std::make_unique<MonoBlend>(sourceChannelCount);
+ lastOutput->connect(&mMonoBlend->input);
+ lastOutput = &mMonoBlend->output;
+ }
// For a pure float graph, there is chance that the data range may be very large.
// So we should clip to a reasonable value that allows a little headroom.
@@ -78,12 +85,6 @@
lastOutput = &mClipper->output;
}
- if (useMonoBlend) {
- mMonoBlend = std::make_unique<MonoBlend>(sourceChannelCount);
- lastOutput->connect(&mMonoBlend->input);
- lastOutput = &mMonoBlend->output;
- }
-
// Expand the number of channels if required.
if (sourceChannelCount == 1 && sinkChannelCount > 1) {
mChannelConverter = std::make_unique<MonoToMultiConverter>(sinkChannelCount);
@@ -94,6 +95,26 @@
return AAUDIO_ERROR_UNIMPLEMENTED;
}
+ // Apply volume ramps for only exclusive streams.
+ if (isExclusive) {
+ // Apply volume ramps to set the left/right audio balance and target volumes.
+ // The signals will be decoupled, volume ramps will be applied, before the signals are
+ // combined again.
+ mMultiToManyConverter = std::make_unique<MultiToManyConverter>(sinkChannelCount);
+ mManyToMultiConverter = std::make_unique<ManyToMultiConverter>(sinkChannelCount);
+ lastOutput->connect(&mMultiToManyConverter->input);
+ for (int i = 0; i < sinkChannelCount; i++) {
+ mVolumeRamps.emplace_back(std::make_unique<RampLinear>(1));
+ mPanningVolumes.emplace_back(1.0f);
+ lastOutput = mMultiToManyConverter->outputs[i].get();
+ lastOutput->connect(&(mVolumeRamps[i].get()->input));
+ lastOutput = &(mVolumeRamps[i].get()->output);
+ lastOutput->connect(mManyToMultiConverter->inputs[i].get());
+ }
+ lastOutput = &mManyToMultiConverter->output;
+ setAudioBalance(audioBalance);
+ }
+
switch (sinkFormat) {
case AUDIO_FORMAT_PCM_FLOAT:
mSink = std::make_unique<SinkFloat>(sinkChannelCount);
@@ -125,9 +146,32 @@
* @param volume between 0.0 and 1.0
*/
void AAudioFlowGraph::setTargetVolume(float volume) {
- mVolumeRamp->setTarget(volume);
+ for (int i = 0; i < mVolumeRamps.size(); i++) {
+ mVolumeRamps[i]->setTarget(volume * mPanningVolumes[i]);
+ }
+ mTargetVolume = volume;
}
+/**
+ * @param audioBalance between -1.0 and 1.0
+ */
+void AAudioFlowGraph::setAudioBalance(float audioBalance) {
+ if (mPanningVolumes.size() >= 2) {
+ float leftMultiplier = 0;
+ float rightMultiplier = 0;
+ mBalance.computeStereoBalance(audioBalance, &leftMultiplier, &rightMultiplier);
+ mPanningVolumes[0] = leftMultiplier;
+ mPanningVolumes[1] = rightMultiplier;
+ mVolumeRamps[0]->setTarget(mTargetVolume * leftMultiplier);
+ mVolumeRamps[1]->setTarget(mTargetVolume * rightMultiplier);
+ }
+}
+
+/**
+ * @param numFrames to slowly adjust for volume changes
+ */
void AAudioFlowGraph::setRampLengthInFrames(int32_t numFrames) {
- mVolumeRamp->setLengthInFrames(numFrames);
+ for (auto& ramp : mVolumeRamps) {
+ ramp->setLengthInFrames(numFrames);
+ }
}
diff --git a/media/libaaudio/src/client/AAudioFlowGraph.h b/media/libaaudio/src/client/AAudioFlowGraph.h
index e719d91..00b6575 100644
--- a/media/libaaudio/src/client/AAudioFlowGraph.h
+++ b/media/libaaudio/src/client/AAudioFlowGraph.h
@@ -23,9 +23,12 @@
#include <system/audio.h>
#include <aaudio/AAudio.h>
+#include <audio_utils/Balance.h>
#include <flowgraph/ClipToRange.h>
+#include <flowgraph/ManyToMultiConverter.h>
#include <flowgraph/MonoBlend.h>
#include <flowgraph/MonoToMultiConverter.h>
+#include <flowgraph/MultiToManyConverter.h>
#include <flowgraph/RampLinear.h>
class AAudioFlowGraph {
@@ -37,13 +40,19 @@
* @param sourceChannelCount
* @param sinkFormat
* @param sinkChannelCount
+ * @param useMonoBlend
+ * @param audioBalance
+ * @param channelMask
+ * @param isExclusive
* @return
*/
aaudio_result_t configure(audio_format_t sourceFormat,
int32_t sourceChannelCount,
audio_format_t sinkFormat,
int32_t sinkChannelCount,
- bool useMonoBlend);
+ bool useMonoBlend,
+ float audioBalance,
+ bool isExclusive);
void process(const void *source, void *destination, int32_t numFrames);
@@ -52,14 +61,27 @@
*/
void setTargetVolume(float volume);
+ /**
+ * @param audioBalance between -1.0 and 1.0
+ */
+ void setAudioBalance(float audioBalance);
+
+ /**
+ * @param numFrames to slowly adjust for volume changes
+ */
void setRampLengthInFrames(int32_t numFrames);
private:
std::unique_ptr<flowgraph::FlowGraphSourceBuffered> mSource;
std::unique_ptr<flowgraph::MonoBlend> mMonoBlend;
- std::unique_ptr<flowgraph::RampLinear> mVolumeRamp;
std::unique_ptr<flowgraph::ClipToRange> mClipper;
std::unique_ptr<flowgraph::MonoToMultiConverter> mChannelConverter;
+ std::unique_ptr<flowgraph::ManyToMultiConverter> mManyToMultiConverter;
+ std::unique_ptr<flowgraph::MultiToManyConverter> mMultiToManyConverter;
+ std::vector<std::unique_ptr<flowgraph::RampLinear>> mVolumeRamps;
+ std::vector<float> mPanningVolumes;
+ float mTargetVolume = 1.0f;
+ android::audio_utils::Balance mBalance;
std::unique_ptr<flowgraph::FlowGraphSink> mSink;
};
diff --git a/media/libaaudio/src/client/AudioEndpoint.cpp b/media/libaaudio/src/client/AudioEndpoint.cpp
index 24888de..e780f4f 100644
--- a/media/libaaudio/src/client/AudioEndpoint.cpp
+++ b/media/libaaudio/src/client/AudioEndpoint.cpp
@@ -139,38 +139,49 @@
);
// ============================ data queue =============================
- descriptor = &pEndpointDescriptor->dataQueueDescriptor;
- ALOGV("configure() data framesPerBurst = %d", descriptor->framesPerBurst);
+ result = configureDataQueue(pEndpointDescriptor->dataQueueDescriptor, direction);
+
+ return result;
+}
+
+aaudio_result_t AudioEndpoint::configureDataQueue(const RingBufferDescriptor& descriptor,
+ aaudio_direction_t direction) {
+ aaudio_result_t result = AudioEndpoint_validateQueueDescriptor("data", &descriptor);
+ if (result != AAUDIO_OK) {
+ return result;
+ }
+
+ ALOGV("configure() data framesPerBurst = %d", descriptor.framesPerBurst);
ALOGV("configure() data readCounterAddress = %p",
- descriptor->readCounterAddress);
+ descriptor.readCounterAddress);
// An example of free running is when the other side is read or written by hardware DMA
// or a DSP. It does not update its counter so we have to update it.
int64_t *remoteCounter = (direction == AAUDIO_DIRECTION_OUTPUT)
- ? descriptor->readCounterAddress // read by other side
- : descriptor->writeCounterAddress; // written by other side
+ ? descriptor.readCounterAddress // read by other side
+ : descriptor.writeCounterAddress; // written by other side
mFreeRunning = (remoteCounter == nullptr);
ALOGV("configure() mFreeRunning = %d", mFreeRunning ? 1 : 0);
- int64_t *readCounterAddress = (descriptor->readCounterAddress == nullptr)
+ int64_t *readCounterAddress = (descriptor.readCounterAddress == nullptr)
? &mDataReadCounter
- : descriptor->readCounterAddress;
- int64_t *writeCounterAddress = (descriptor->writeCounterAddress == nullptr)
+ : descriptor.readCounterAddress;
+ int64_t *writeCounterAddress = (descriptor.writeCounterAddress == nullptr)
? &mDataWriteCounter
- : descriptor->writeCounterAddress;
+ : descriptor.writeCounterAddress;
// Clear buffer to avoid an initial glitch on some devices.
- size_t bufferSizeBytes = descriptor->capacityInFrames * descriptor->bytesPerFrame;
- memset(descriptor->dataAddress, 0, bufferSizeBytes);
+ size_t bufferSizeBytes = descriptor.capacityInFrames * descriptor.bytesPerFrame;
+ memset(descriptor.dataAddress, 0, bufferSizeBytes);
mDataQueue = std::make_unique<FifoBufferIndirect>(
- descriptor->bytesPerFrame,
- descriptor->capacityInFrames,
+ descriptor.bytesPerFrame,
+ descriptor.capacityInFrames,
readCounterAddress,
writeCounterAddress,
- descriptor->dataAddress
+ descriptor.dataAddress
);
- uint32_t threshold = descriptor->capacityInFrames / 2;
+ uint32_t threshold = descriptor.capacityInFrames / 2;
mDataQueue->setThreshold(threshold);
return result;
}
@@ -181,47 +192,66 @@
}
int32_t AudioEndpoint::getEmptyFramesAvailable(WrappingBuffer *wrappingBuffer) {
- return mDataQueue->getEmptyRoomAvailable(wrappingBuffer);
+ return mDataQueue == nullptr ? 0 : mDataQueue->getEmptyRoomAvailable(wrappingBuffer);
}
int32_t AudioEndpoint::getEmptyFramesAvailable() {
- return mDataQueue->getEmptyFramesAvailable();
+ return mDataQueue == nullptr ? 0 : mDataQueue->getEmptyFramesAvailable();
}
int32_t AudioEndpoint::getFullFramesAvailable(WrappingBuffer *wrappingBuffer) {
- return mDataQueue->getFullDataAvailable(wrappingBuffer);
+ return mDataQueue == nullptr ? 0 : mDataQueue->getFullDataAvailable(wrappingBuffer);
}
int32_t AudioEndpoint::getFullFramesAvailable() {
- return mDataQueue->getFullFramesAvailable();
+ return mDataQueue == nullptr ? 0 : mDataQueue->getFullFramesAvailable();
+}
+
+android::fifo_frames_t AudioEndpoint::read(void *buffer, android::fifo_frames_t numFrames) {
+ return mDataQueue == nullptr ? 0 : mDataQueue->read(buffer, numFrames);
+}
+
+android::fifo_frames_t AudioEndpoint::write(void *buffer, android::fifo_frames_t numFrames) {
+ return mDataQueue == nullptr ? 0 : mDataQueue->write(buffer, numFrames);
}
void AudioEndpoint::advanceWriteIndex(int32_t deltaFrames) {
- mDataQueue->advanceWriteIndex(deltaFrames);
+ if (mDataQueue != nullptr) {
+ mDataQueue->advanceWriteIndex(deltaFrames);
+ }
}
void AudioEndpoint::advanceReadIndex(int32_t deltaFrames) {
- mDataQueue->advanceReadIndex(deltaFrames);
+ if (mDataQueue != nullptr) {
+ mDataQueue->advanceReadIndex(deltaFrames);
+ }
}
void AudioEndpoint::setDataReadCounter(fifo_counter_t framesRead) {
- mDataQueue->setReadCounter(framesRead);
+ if (mDataQueue != nullptr) {
+ mDataQueue->setReadCounter(framesRead);
+ }
}
fifo_counter_t AudioEndpoint::getDataReadCounter() const {
- return mDataQueue->getReadCounter();
+ return mDataQueue == nullptr ? 0 : mDataQueue->getReadCounter();
}
void AudioEndpoint::setDataWriteCounter(fifo_counter_t framesRead) {
- mDataQueue->setWriteCounter(framesRead);
+ if (mDataQueue != nullptr) {
+ mDataQueue->setWriteCounter(framesRead);
+ }
}
fifo_counter_t AudioEndpoint::getDataWriteCounter() const {
- return mDataQueue->getWriteCounter();
+ return mDataQueue == nullptr ? 0 : mDataQueue->getWriteCounter();
}
int32_t AudioEndpoint::setBufferSizeInFrames(int32_t requestedFrames,
int32_t *actualFrames) {
+ if (mDataQueue == nullptr) {
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
if (requestedFrames < ENDPOINT_DATA_QUEUE_SIZE_MIN) {
requestedFrames = ENDPOINT_DATA_QUEUE_SIZE_MIN;
}
@@ -231,11 +261,11 @@
}
int32_t AudioEndpoint::getBufferSizeInFrames() const {
- return mDataQueue->getThreshold();
+ return mDataQueue == nullptr ? 0 : mDataQueue->getThreshold();
}
int32_t AudioEndpoint::getBufferCapacityInFrames() const {
- return (int32_t)mDataQueue->getBufferCapacityInFrames();
+ return mDataQueue == nullptr ? 0 : (int32_t)mDataQueue->getBufferCapacityInFrames();
}
void AudioEndpoint::dump() const {
@@ -244,5 +274,7 @@
}
void AudioEndpoint::eraseDataMemory() {
- mDataQueue->eraseMemory();
+ if (mDataQueue != nullptr) {
+ mDataQueue->eraseMemory();
+ }
}
diff --git a/media/libaaudio/src/client/AudioEndpoint.h b/media/libaaudio/src/client/AudioEndpoint.h
index b3dbc20..01dd05a 100644
--- a/media/libaaudio/src/client/AudioEndpoint.h
+++ b/media/libaaudio/src/client/AudioEndpoint.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_AAUDIO_AUDIO_ENDPOINT_H
#define ANDROID_AAUDIO_AUDIO_ENDPOINT_H
+#include <mutex>
+
#include <aaudio/AAudio.h>
#include "binding/AAudioServiceMessage.h"
@@ -42,6 +44,9 @@
aaudio_result_t configure(const EndpointDescriptor *pEndpointDescriptor,
aaudio_direction_t direction);
+ aaudio_result_t configureDataQueue(const RingBufferDescriptor &descriptor,
+ aaudio_direction_t direction);
+
/**
* Read from a command passed up from the Server.
* @return 1 if command received, 0 for no command, or negative error.
@@ -56,6 +61,10 @@
int32_t getFullFramesAvailable();
+ android::fifo_frames_t read(void* buffer, android::fifo_frames_t numFrames);
+
+ android::fifo_frames_t write(void* buffer, android::fifo_frames_t numFrames);
+
void advanceReadIndex(int32_t deltaFrames);
void advanceWriteIndex(int32_t deltaFrames);
@@ -85,11 +94,21 @@
int32_t getBufferCapacityInFrames() const;
+ void setThreshold(int32_t frames) {
+ mDataQueue->setThreshold(frames);
+ }
+
+ int32_t getThreshold() {
+ return mDataQueue->getThreshold();
+ }
+
/**
* Write zeros to the data queue memory.
*/
void eraseDataMemory();
+ void freeDataQueue();
+
void dump() const;
private:
@@ -98,6 +117,8 @@
bool mFreeRunning{false};
android::fifo_counter_t mDataReadCounter{0}; // only used if free-running
android::fifo_counter_t mDataWriteCounter{0}; // only used if free-running
+
+ std::mutex mDataQueueLock;
};
} // namespace aaudio
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 1b8e224..9f0564f 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -81,8 +81,6 @@
aaudio_result_t AudioStreamInternal::open(const AudioStreamBuilder &builder) {
aaudio_result_t result = AAUDIO_OK;
- int32_t framesPerBurst;
- int32_t framesPerHardwareBurst;
AAudioStreamRequest request;
AAudioStreamConfiguration configurationOutput;
@@ -97,9 +95,6 @@
return result;
}
- const int32_t burstMinMicros = android::AudioSystem::getAAudioHardwareBurstMinUsec();
- int32_t burstMicros = 0;
-
const audio_format_t requestedFormat = getFormat();
// We have to do volume scaling. So we prefer FLOAT format.
if (requestedFormat == AUDIO_FORMAT_DEFAULT) {
@@ -215,12 +210,28 @@
goto error;
}
- framesPerHardwareBurst = mEndpointDescriptor.dataQueueDescriptor.framesPerBurst;
+ if ((result = configureDataInformation(builder.getFramesPerDataCallback())) != AAUDIO_OK) {
+ goto error;
+ }
+
+ setState(AAUDIO_STREAM_STATE_OPEN);
+
+ return result;
+
+error:
+ safeReleaseClose();
+ return result;
+}
+
+aaudio_result_t AudioStreamInternal::configureDataInformation(int32_t callbackFrames) {
+ int32_t framesPerHardwareBurst = mEndpointDescriptor.dataQueueDescriptor.framesPerBurst;
// Scale up the burst size to meet the minimum equivalent in microseconds.
// This is to avoid waking the CPU too often when the HW burst is very small
// or at high sample rates.
- framesPerBurst = framesPerHardwareBurst;
+ int32_t framesPerBurst = framesPerHardwareBurst;
+ int32_t burstMicros = 0;
+ const int32_t burstMinMicros = android::AudioSystem::getAAudioHardwareBurstMinUsec();
do {
if (burstMicros > 0) { // skip first loop
framesPerBurst *= 2;
@@ -233,8 +244,7 @@
// Validate final burst size.
if (framesPerBurst < MIN_FRAMES_PER_BURST || framesPerBurst > MAX_FRAMES_PER_BURST) {
ALOGE("%s - framesPerBurst out of range = %d", __func__, framesPerBurst);
- result = AAUDIO_ERROR_OUT_OF_RANGE;
- goto error;
+ return AAUDIO_ERROR_OUT_OF_RANGE;
}
setFramesPerBurst(framesPerBurst); // only save good value
@@ -242,26 +252,21 @@
if (mBufferCapacityInFrames < getFramesPerBurst()
|| mBufferCapacityInFrames > MAX_BUFFER_CAPACITY_IN_FRAMES) {
ALOGE("%s - bufferCapacity out of range = %d", __func__, mBufferCapacityInFrames);
- result = AAUDIO_ERROR_OUT_OF_RANGE;
- goto error;
+ return AAUDIO_ERROR_OUT_OF_RANGE;
}
mClockModel.setSampleRate(getSampleRate());
mClockModel.setFramesPerBurst(framesPerHardwareBurst);
if (isDataCallbackSet()) {
- mCallbackFrames = builder.getFramesPerDataCallback();
+ mCallbackFrames = callbackFrames;
if (mCallbackFrames > getBufferCapacity() / 2) {
ALOGW("%s - framesPerCallback too big = %d, capacity = %d",
__func__, mCallbackFrames, getBufferCapacity());
- result = AAUDIO_ERROR_OUT_OF_RANGE;
- goto error;
-
+ return AAUDIO_ERROR_OUT_OF_RANGE;
} else if (mCallbackFrames < 0) {
ALOGW("%s - framesPerCallback negative", __func__);
- result = AAUDIO_ERROR_OUT_OF_RANGE;
- goto error;
-
+ return AAUDIO_ERROR_OUT_OF_RANGE;
}
if (mCallbackFrames == AAUDIO_UNSPECIFIED) {
mCallbackFrames = getFramesPerBurst();
@@ -272,12 +277,15 @@
}
// Exclusive output streams should combine channels when mono audio adjustment
- // is enabled.
+ // is enabled. They should also adjust for audio balance.
if ((getDirection() == AAUDIO_DIRECTION_OUTPUT) &&
(getSharingMode() == AAUDIO_SHARING_MODE_EXCLUSIVE)) {
bool isMasterMono = false;
android::AudioSystem::getMasterMono(&isMasterMono);
setRequireMonoBlend(isMasterMono);
+ float audioBalance = 0;
+ android::AudioSystem::getMasterBalance(&audioBalance);
+ setAudioBalance(audioBalance);
}
// For debugging and analyzing the distribution of MMAP timestamps.
@@ -299,14 +307,7 @@
}
setBufferSize(mBufferCapacityInFrames / 2); // Default buffer size to match Q
-
- setState(AAUDIO_STREAM_STATE_OPEN);
-
- return result;
-
-error:
- safeReleaseClose();
- return result;
+ return AAUDIO_OK;
}
// This must be called under mStreamLock.
@@ -354,6 +355,60 @@
}
}
+aaudio_result_t AudioStreamInternal::exitStandby_l() {
+ AudioEndpointParcelable endpointParcelable;
+ // The stream is in standby mode, copy all available data and then close the duplicated
+ // shared file descriptor so that it won't cause issue when the HAL try to reallocate new
+ // shared file descriptor when exiting from standby.
+ // Cache current read counter, which will be reset to new read and write counter
+ // when the new data queue and endpoint are reconfigured.
+ const android::fifo_counter_t readCounter = mAudioEndpoint->getDataReadCounter();
+ // Cache the buffer size which may be from client.
+ const int32_t previousBufferSize = mBufferSizeInFrames;
+ // Copy all available data from current data queue.
+ uint8_t buffer[getBufferCapacity() * getBytesPerFrame()];
+ android::fifo_frames_t fullFramesAvailable =
+ mAudioEndpoint->read(buffer, getBufferCapacity());
+ mEndPointParcelable.closeDataFileDescriptor();
+ aaudio_result_t result = mServiceInterface.exitStandby(
+ mServiceStreamHandle, endpointParcelable);
+ if (result != AAUDIO_OK) {
+ ALOGE("Failed to exit standby, error=%d", result);
+ goto exit;
+ }
+ // Reconstruct data queue descriptor using new shared file descriptor.
+ mEndPointParcelable.updateDataFileDescriptor(&endpointParcelable);
+ result = mEndPointParcelable.resolveDataQueue(&mEndpointDescriptor.dataQueueDescriptor);
+ if (result != AAUDIO_OK) {
+ ALOGE("Failed to resolve data queue after exiting standby, error=%d", result);
+ goto exit;
+ }
+ // Reconfigure audio endpoint with new data queue descriptor.
+ mAudioEndpoint->configureDataQueue(
+ mEndpointDescriptor.dataQueueDescriptor, getDirection());
+ // Set read and write counters with previous read counter, the later write action
+ // will make the counter at the correct place.
+ mAudioEndpoint->setDataReadCounter(readCounter);
+ mAudioEndpoint->setDataWriteCounter(readCounter);
+ result = configureDataInformation(mCallbackFrames);
+ if (result != AAUDIO_OK) {
+ ALOGE("Failed to configure data information after exiting standby, error=%d", result);
+ goto exit;
+ }
+ // Write data from previous data buffer to new endpoint.
+ if (android::fifo_frames_t framesWritten =
+ mAudioEndpoint->write(buffer, fullFramesAvailable);
+ framesWritten != fullFramesAvailable) {
+ ALOGW("Some data lost after exiting standby, frames written: %d, "
+ "frames to write: %d", framesWritten, fullFramesAvailable);
+ }
+ // Reset previous buffer size as it may be requested by the client.
+ setBufferSize(previousBufferSize);
+
+exit:
+ return result;
+}
+
/*
* It normally takes about 20-30 msec to start a stream on the server.
* But the first time can take as much as 200-300 msec. The HW
@@ -390,8 +445,15 @@
prepareBuffersForStart(); // tell subclasses to get ready
aaudio_result_t result = mServiceInterface.startStream(mServiceStreamHandle);
- if (result == AAUDIO_ERROR_INVALID_HANDLE) {
- ALOGD("%s() INVALID_HANDLE, stream was probably stolen", __func__);
+ if (result == AAUDIO_ERROR_STANDBY) {
+ // The stream is at standby mode. Need to exit standby before starting the stream.
+ result = exitStandby_l();
+ if (result == AAUDIO_OK) {
+ result = mServiceInterface.startStream(mServiceStreamHandle);
+ }
+ }
+ if (result != AAUDIO_OK) {
+ ALOGD("%s() error = %d, stream was probably stolen", __func__, result);
// Stealing was added in R. Coerce result to improve backward compatibility.
result = AAUDIO_ERROR_DISCONNECTED;
setState(AAUDIO_STREAM_STATE_DISCONNECTED);
@@ -411,6 +473,7 @@
result = createThread_l(periodNanos, aaudio_callback_thread_proc, this);
}
if (result != AAUDIO_OK) {
+ // TODO(b/214607638): Do we want to roll back to original state or keep as disconnected?
setState(originalState);
}
return result;
diff --git a/media/libaaudio/src/client/AudioStreamInternal.h b/media/libaaudio/src/client/AudioStreamInternal.h
index eab1382..2367572 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.h
+++ b/media/libaaudio/src/client/AudioStreamInternal.h
@@ -184,9 +184,14 @@
aaudio_result_t writeNowWithConversion(const void *buffer,
int32_t numFrames);
+ // Exit the stream from standby, will reconstruct data path.
+ aaudio_result_t exitStandby_l() REQUIRES(mStreamLock);
+
// Adjust timing model based on timestamp from service.
void processTimestamp(uint64_t position, int64_t time);
+ aaudio_result_t configureDataInformation(int32_t callbackFrames);
+
// Thread on other side of FIFO will have wakeup jitter.
// By delaying slightly we can avoid waking up before other side is ready.
const int32_t mWakeupDelayNanos; // delay past typical wakeup jitter
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
index c17c7a0..450d390 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
@@ -53,7 +53,9 @@
getSamplesPerFrame(),
getDeviceFormat(),
getDeviceChannelCount(),
- getRequireMonoBlend());
+ getRequireMonoBlend(),
+ getAudioBalance(),
+ (getSharingMode() == AAUDIO_SHARING_MODE_EXCLUSIVE));
if (result != AAUDIO_OK) {
safeReleaseClose();
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index 73432af..06f05b0 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -602,6 +602,7 @@
void AudioStream::setDuckAndMuteVolume(float duckAndMuteVolume) {
ALOGD("%s() to %f", __func__, duckAndMuteVolume);
+ std::lock_guard<std::mutex> lock(mStreamLock);
mDuckAndMuteVolume = duckAndMuteVolume;
doSetVolume(); // apply this change
}
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index a3af753..5fb4528 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -281,6 +281,10 @@
return mRequireMonoBlend;
}
+ float getAudioBalance() const {
+ return mAudioBalance;
+ }
+
/**
* This is only valid after setChannelMask() and setFormat()
* have been called.
@@ -642,6 +646,13 @@
mRequireMonoBlend = requireMonoBlend;
}
+ /**
+ * This should not be called after the open() call.
+ */
+ void setAudioBalance(float audioBalance) {
+ mAudioBalance = audioBalance;
+ }
+
std::string mMetricsId; // set once during open()
std::mutex mStreamLock;
@@ -684,6 +695,7 @@
aaudio_allowed_capture_policy_t mAllowedCapturePolicy = AAUDIO_ALLOW_CAPTURE_BY_ALL;
bool mIsPrivacySensitive = false;
bool mRequireMonoBlend = false;
+ float mAudioBalance = 0;
int32_t mSessionId = AAUDIO_UNSPECIFIED;
diff --git a/media/libaaudio/src/flowgraph/MultiToManyConverter.cpp b/media/libaaudio/src/flowgraph/MultiToManyConverter.cpp
new file mode 100644
index 0000000..f074364
--- /dev/null
+++ b/media/libaaudio/src/flowgraph/MultiToManyConverter.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2015 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 <unistd.h>
+#include "FlowGraphNode.h"
+#include "MultiToManyConverter.h"
+
+using namespace flowgraph;
+
+MultiToManyConverter::MultiToManyConverter(int32_t channelCount)
+ : outputs(channelCount)
+ , input(*this, channelCount) {
+ for (int i = 0; i < channelCount; i++) {
+ outputs[i] = std::make_unique<FlowGraphPortFloatOutput>(*this, 1);
+ }
+}
+
+MultiToManyConverter::~MultiToManyConverter() = default;
+
+int32_t MultiToManyConverter::onProcess(int32_t numFrames) {
+ int32_t channelCount = input.getSamplesPerFrame();
+
+ for (int ch = 0; ch < channelCount; ch++) {
+ const float *inputBuffer = input.getBuffer() + ch;
+ float *outputBuffer = outputs[ch]->getBuffer();
+
+ for (int i = 0; i < numFrames; i++) {
+ *outputBuffer++ = *inputBuffer;
+ inputBuffer += channelCount;
+ }
+ }
+
+ return numFrames;
+}
+
diff --git a/media/libaaudio/src/flowgraph/MultiToManyConverter.h b/media/libaaudio/src/flowgraph/MultiToManyConverter.h
new file mode 100644
index 0000000..de31475
--- /dev/null
+++ b/media/libaaudio/src/flowgraph/MultiToManyConverter.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2015 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 FLOWGRAPH_MULTI_TO_MANY_CONVERTER_H
+#define FLOWGRAPH_MULTI_TO_MANY_CONVERTER_H
+
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "FlowGraphNode.h"
+
+namespace flowgraph {
+
+/**
+ * Convert a multi-channel interleaved stream to multiple mono-channel
+ * outputs
+ */
+ class MultiToManyConverter : public FlowGraphNode {
+ public:
+ explicit MultiToManyConverter(int32_t channelCount);
+
+ virtual ~MultiToManyConverter();
+
+ int32_t onProcess(int32_t numFrames) override;
+
+ const char *getName() override {
+ return "MultiToManyConverter";
+ }
+
+ std::vector<std::unique_ptr<flowgraph::FlowGraphPortFloatOutput>> outputs;
+ flowgraph::FlowGraphPortFloatInput input;
+ };
+
+} /* namespace flowgraph */
+
+#endif //FLOWGRAPH_MULTI_TO_MANY_CONVERTER_H
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index df7d4cf..d9f12a5 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -557,7 +557,7 @@
case AAUDIO_STREAM_STATE_STARTED:
result = mAudioRecord->getPosition(&position);
if (result == OK) {
- mFramesWritten.update32(position);
+ mFramesWritten.update32((int32_t)position);
}
break;
case AAUDIO_STREAM_STATE_STOPPING:
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index 17a6d0c..6f1dc92 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -508,7 +508,7 @@
case AAUDIO_STREAM_STATE_PAUSED:
result = mAudioTrack->getPosition(&position);
if (result == OK) {
- mFramesRead.update32(position);
+ mFramesRead.update32((int32_t)position);
}
break;
default:
diff --git a/media/libaaudio/src/utility/MonotonicCounter.h b/media/libaaudio/src/utility/MonotonicCounter.h
index 313ccbd..51eb69b 100644
--- a/media/libaaudio/src/utility/MonotonicCounter.h
+++ b/media/libaaudio/src/utility/MonotonicCounter.h
@@ -41,7 +41,12 @@
}
/**
- * advance the current value to match the counter
+ * Advance the current value to match the counter.
+ *
+ * Note that it will take several million years for the 64-bit
+ * counters to wrap around.
+ * So we do not use __builtin_sub_overflow.
+ * We want to know if overflow happens because of a bug.
*/
void catchUpTo(int64_t counter) {
if ((counter - mCounter64) > 0) {
@@ -74,7 +79,8 @@
* @return current value of the 64-bit counter
*/
int64_t update32(int32_t counter32) {
- int32_t delta = counter32 - mCounter32;
+ int32_t delta;
+ __builtin_sub_overflow(counter32, mCounter32, &delta);
// protect against the mCounter64 going backwards
if (delta > 0) {
mCounter64 += delta;
@@ -108,5 +114,4 @@
int32_t mCounter32 = 0;
};
-
#endif //UTILITY_MONOTONIC_COUNTER_H
diff --git a/media/libaaudio/tests/Android.bp b/media/libaaudio/tests/Android.bp
index ea00a5a..4b45909 100644
--- a/media/libaaudio/tests/Android.bp
+++ b/media/libaaudio/tests/Android.bp
@@ -13,6 +13,11 @@
"-Wall",
"-Werror",
],
+
+ sanitize: {
+ integer_overflow: true,
+ misc_undefined: ["bounds"],
+ },
}
cc_test {
@@ -146,6 +151,18 @@
],
}
+cc_test {
+ name: "test_monotonic_counter",
+ defaults: ["libaaudio_tests_defaults"],
+ srcs: ["test_monotonic_counter.cpp"],
+ shared_libs: [
+ "libaaudio_internal",
+ "libbinder",
+ "libcutils",
+ "libutils",
+ ],
+}
+
cc_binary {
name: "test_return_stop",
defaults: ["libaaudio_tests_defaults"],
diff --git a/media/libaaudio/tests/test_monotonic_counter.cpp b/media/libaaudio/tests/test_monotonic_counter.cpp
new file mode 100644
index 0000000..5cbbaf7
--- /dev/null
+++ b/media/libaaudio/tests/test_monotonic_counter.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2022 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.
+ */
+
+/*
+ * Test MonotonicCounter
+ */
+
+#include <iostream>
+
+#include <gtest/gtest.h>
+
+#include "utility/MonotonicCounter.h"
+
+TEST(test_monotonic_counter, builtin_wrap) {
+ int32_t x = 0x7FFFFFF0;
+ int32_t y = 0x80000010;
+ int32_t delta;
+ // delta = y - x; // This would cause a numeric overflow!
+ __builtin_sub_overflow(y, x, &delta);
+ ASSERT_EQ(0x20, delta);
+}
+
+// test updating past some overflow points
+TEST(test_monotonic_counter, mono_counter_update32_wrap) {
+ MonotonicCounter counter;
+ ASSERT_EQ(0, counter.get());
+
+ static constexpr uint32_t x = (uint32_t) 0x7FFFFFF0;
+ counter.update32(x);
+ ASSERT_EQ((int64_t)0x7FFFFFF0, counter.get());
+
+ static constexpr uint32_t y = (uint32_t) 0x80000010;
+ counter.update32(y);
+ ASSERT_EQ((int64_t)0x80000010, counter.get());
+
+ counter.update32(0);
+ ASSERT_EQ((int64_t)0x100000000, counter.get());
+}
+
+TEST(test_monotonic_counter, mono_counter_roundup) {
+ MonotonicCounter counter;
+ static constexpr uint32_t x = 2345;
+ counter.update32(x);
+ ASSERT_EQ((int64_t)x, counter.get());
+
+ counter.roundUp64(100);
+ ASSERT_EQ((int64_t)2400, counter.get());
+}
+
+TEST(test_monotonic_counter, mono_counter_catchup) {
+ MonotonicCounter counter;
+ counter.update32(7654);
+ counter.catchUpTo(5000); // already past 5000 so no change
+ ASSERT_EQ((int64_t)7654, counter.get());
+ counter.catchUpTo(9876); // jumps
+ ASSERT_EQ((int64_t)9876, counter.get());
+}
+
+TEST(test_monotonic_counter, mono_counter_increment) {
+ MonotonicCounter counter;
+ counter.update32(1000);
+ counter.increment(-234); // will not go backwards
+ ASSERT_EQ((int64_t)1000, counter.get());
+ counter.increment(96); // advances
+ ASSERT_EQ((int64_t)1096, counter.get());
+}
+
+TEST(test_monotonic_counter, mono_counter_reset) {
+ MonotonicCounter counter;
+ counter.update32(1000);
+ // Counter is monotonic and should not go backwards.
+ counter.update32(500); // No change because 32-bit counter is already past 1000.
+ ASSERT_EQ((int64_t)1000, counter.get());
+
+ counter.reset32();
+ counter.update32(500);
+ ASSERT_EQ((int64_t)1500, counter.get());
+}
diff --git a/media/libaaudio/tests/test_steal_exclusive.cpp b/media/libaaudio/tests/test_steal_exclusive.cpp
index 5cb005c..ca4f3d6 100644
--- a/media/libaaudio/tests/test_steal_exclusive.cpp
+++ b/media/libaaudio/tests/test_steal_exclusive.cpp
@@ -114,7 +114,7 @@
mCloseEnabled = enabled;
}
- void restartStream() {
+ aaudio_result_t restartStream() {
int retriesLeft = mMaxRetries;
aaudio_result_t result;
do {
@@ -130,6 +130,7 @@
mName.c_str(),
AAudio_convertResultToText(result));
} while (retriesLeft-- > 0 && result != AAUDIO_OK);
+ return result;
}
aaudio_data_callback_result_t onAudioReady(
@@ -238,6 +239,12 @@
return AAudioStream_requestStart(mStream);
}
+ aaudio_result_t pause() {
+ std::lock_guard<std::mutex> lock(mLock);
+ if (mStream == nullptr) return 0;
+ return AAudioStream_requestPause(mStream);
+ }
+
aaudio_result_t stop() {
std::lock_guard<std::mutex> lock(mLock);
if (mStream == nullptr) return 0;
@@ -326,9 +333,10 @@
}
static void s_usage() {
- printf("test_steal_exclusive [-i] [-r{maxRetries}] [-d{delay}] -s -c{flag}\n");
+ printf("test_steal_exclusive [-i] [-r{maxRetries}] [-d{delay}] [-p{pausedTime}]-s -c{flag}\n");
printf(" -i direction INPUT, otherwise OUTPUT\n");
printf(" -d Delay open by milliseconds, default = 0\n");
+ printf(" -p Pause first stream then sleep for msec before opening second streams, default = 0\n");
printf(" -r max Retries in the error callback, default = 1\n");
printf(" -s try to open in SHARED mode\n");
printf(" -c enable or disabling Closing of the stream with 0/1, default = 1\n");
@@ -344,6 +352,7 @@
int openDelayMillis = 0;
bool closeEnabled = true;
aaudio_sharing_mode_t requestedSharingMode = AAUDIO_SHARING_MODE_EXCLUSIVE;
+ int pausedMillis = 0;
// Make printf print immediately so that debug info is not stuck
// in a buffer if we hang or crash.
@@ -366,6 +375,9 @@
case 'i':
direction = AAUDIO_DIRECTION_INPUT;
break;
+ case 'p':
+ pausedMillis = atoi(&arg[2]);
+ break;
case 'r':
maxRetries = atoi(&arg[2]);
break;
@@ -428,6 +440,12 @@
}
}
+ if (pausedMillis > 0) {
+ printf("Pausing the VICTIM for %d millis before starting THIEF -----\n", pausedMillis);
+ victim.pause();
+ usleep(pausedMillis * 1000);
+ }
+
printf("Trying to start the THIEF stream, which may steal the VICTIM MMAP resource -----\n");
result = thief.openAudioStream(direction, requestedSharingMode);
if (result != AAUDIO_OK) {
@@ -443,6 +461,25 @@
errorCount++;
}
+ if (pausedMillis > 0) {
+ result = victim.start();
+ printf("Restarting VICTIM, AAudioStream_requestStart(VICTIM) returned %d "
+ ">>>>>>>>>>>>>>>>>>>>>>\n", result);
+ if (result == AAUDIO_ERROR_DISCONNECTED) {
+ // The stream is disconnected due to thief steal the resource
+ printf("VICTIM was disconnected while hanging as the THIEF "
+ "stole the resource >>>>>>>>>>>>>>>>>>>>>>\n");
+ result = victim.restartStream();
+ printf("Restarting VICTIM, AAudioStream_requestStart(VICTIM) returned %d "
+ ">>>>>>>>>>>>>>>>>>>>>>\n", result);
+ if (result != AAUDIO_OK) {
+ errorCount++;
+ }
+ } else {
+ errorCount++;
+ }
+ }
+
// Give stream time to advance.
usleep(SLEEP_DURATION_MSEC * 1000);
diff --git a/media/libaudioclient/AidlConversion.cpp b/media/libaudioclient/AidlConversion.cpp
index f81aa87..11724e0 100644
--- a/media/libaudioclient/AidlConversion.cpp
+++ b/media/libaudioclient/AidlConversion.cpp
@@ -601,6 +601,11 @@
AudioDeviceType::OUT_SPEAKER,
AudioDeviceDescription::CONNECTION_BT_LE())
},
+ {
+ AUDIO_DEVICE_OUT_BLE_BROADCAST, make_AudioDeviceDescription(
+ AudioDeviceType::OUT_BROADCAST,
+ AudioDeviceDescription::CONNECTION_BT_LE())
+ },
// AUDIO_DEVICE_IN_AMBIENT and IN_COMMUNICATION are removed since they were deprecated.
{
AUDIO_DEVICE_IN_BUILTIN_MIC, make_AudioDeviceDescription(
@@ -1434,6 +1439,8 @@
return AUDIO_INPUT_FLAG_HW_AV_SYNC;
case AudioInputFlags::DIRECT:
return AUDIO_INPUT_FLAG_DIRECT;
+ case AudioInputFlags::ULTRASOUND:
+ return AUDIO_INPUT_FLAG_ULTRASOUND;
}
return unexpected(BAD_VALUE);
}
@@ -1459,6 +1466,8 @@
return AudioInputFlags::HW_AV_SYNC;
case AUDIO_INPUT_FLAG_DIRECT:
return AudioInputFlags::DIRECT;
+ case AUDIO_INPUT_FLAG_ULTRASOUND:
+ return AudioInputFlags::ULTRASOUND;
}
return unexpected(BAD_VALUE);
}
@@ -1498,6 +1507,10 @@
return AUDIO_OUTPUT_FLAG_INCALL_MUSIC;
case AudioOutputFlags::GAPLESS_OFFLOAD:
return AUDIO_OUTPUT_FLAG_GAPLESS_OFFLOAD;
+ case AudioOutputFlags::ULTRASOUND:
+ return AUDIO_OUTPUT_FLAG_ULTRASOUND;
+ case AudioOutputFlags::SPATIALIZER:
+ return AUDIO_OUTPUT_FLAG_SPATIALIZER;
}
return unexpected(BAD_VALUE);
}
@@ -1539,6 +1552,10 @@
return AudioOutputFlags::INCALL_MUSIC;
case AUDIO_OUTPUT_FLAG_GAPLESS_OFFLOAD:
return AudioOutputFlags::GAPLESS_OFFLOAD;
+ case AUDIO_OUTPUT_FLAG_ULTRASOUND:
+ return AudioOutputFlags::ULTRASOUND;
+ case AUDIO_OUTPUT_FLAG_SPATIALIZER:
+ return AudioOutputFlags::SPATIALIZER;
}
return unexpected(BAD_VALUE);
}
@@ -1744,6 +1761,8 @@
return AUDIO_SOURCE_UNPROCESSED;
case AudioSource::VOICE_PERFORMANCE:
return AUDIO_SOURCE_VOICE_PERFORMANCE;
+ case AudioSource::ULTRASOUND:
+ return AUDIO_SOURCE_ULTRASOUND;
case AudioSource::ECHO_REFERENCE:
return AUDIO_SOURCE_ECHO_REFERENCE;
case AudioSource::FM_TUNER:
@@ -1781,6 +1800,8 @@
return AudioSource::UNPROCESSED;
case AUDIO_SOURCE_VOICE_PERFORMANCE:
return AudioSource::VOICE_PERFORMANCE;
+ case AUDIO_SOURCE_ULTRASOUND:
+ return AudioSource::ULTRASOUND;
case AUDIO_SOURCE_ECHO_REFERENCE:
return AudioSource::ECHO_REFERENCE;
case AUDIO_SOURCE_FM_TUNER:
@@ -2141,6 +2162,8 @@
return AUDIO_CONTENT_TYPE_MOVIE;
case AudioContentType::SONIFICATION:
return AUDIO_CONTENT_TYPE_SONIFICATION;
+ case AudioContentType::ULTRASOUND:
+ return AUDIO_CONTENT_TYPE_ULTRASOUND;
}
return unexpected(BAD_VALUE);
}
@@ -2158,6 +2181,8 @@
return AudioContentType::MOVIE;
case AUDIO_CONTENT_TYPE_SONIFICATION:
return AudioContentType::SONIFICATION;
+ case AUDIO_CONTENT_TYPE_ULTRASOUND:
+ return AudioContentType::ULTRASOUND;
}
return unexpected(BAD_VALUE);
}
@@ -3314,4 +3339,53 @@
return trackSecondaryOutputInfo;
}
+ConversionResult<audio_direct_mode_t>
+aidl2legacy_AudioDirectMode_audio_direct_mode_t(media::AudioDirectMode aidl) {
+ switch (aidl) {
+ case media::AudioDirectMode::NONE:
+ return AUDIO_DIRECT_NOT_SUPPORTED;
+ case media::AudioDirectMode::OFFLOAD:
+ return AUDIO_DIRECT_OFFLOAD_SUPPORTED;
+ case media::AudioDirectMode::OFFLOAD_GAPLESS:
+ return AUDIO_DIRECT_OFFLOAD_GAPLESS_SUPPORTED;
+ case media::AudioDirectMode::BITSTREAM:
+ return AUDIO_DIRECT_BITSTREAM_SUPPORTED;
+ }
+ return unexpected(BAD_VALUE);
+}
+ConversionResult<media::AudioDirectMode>
+legacy2aidl_audio_direct_mode_t_AudioDirectMode(audio_direct_mode_t legacy) {
+ switch (legacy) {
+ case AUDIO_DIRECT_NOT_SUPPORTED:
+ return media::AudioDirectMode::NONE;
+ case AUDIO_DIRECT_OFFLOAD_SUPPORTED:
+ return media::AudioDirectMode::OFFLOAD;
+ case AUDIO_DIRECT_OFFLOAD_GAPLESS_SUPPORTED:
+ return media::AudioDirectMode::OFFLOAD_GAPLESS;
+ case AUDIO_DIRECT_BITSTREAM_SUPPORTED:
+ return media::AudioDirectMode::BITSTREAM;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<audio_direct_mode_t> aidl2legacy_int32_t_audio_direct_mode_t_mask(int32_t aidl) {
+ using LegacyMask = std::underlying_type_t<audio_direct_mode_t>;
+
+ LegacyMask converted = VALUE_OR_RETURN(
+ (convertBitmask<LegacyMask, int32_t, audio_direct_mode_t, media::AudioDirectMode>(
+ aidl, aidl2legacy_AudioDirectMode_audio_direct_mode_t,
+ indexToEnum_index<media::AudioDirectMode>,
+ enumToMask_bitmask<LegacyMask, audio_direct_mode_t>)));
+ return static_cast<audio_direct_mode_t>(converted);
+}
+ConversionResult<int32_t> legacy2aidl_audio_direct_mode_t_int32_t_mask(audio_direct_mode_t legacy) {
+ using LegacyMask = std::underlying_type_t<audio_direct_mode_t>;
+
+ LegacyMask legacyMask = static_cast<LegacyMask>(legacy);
+ return convertBitmask<int32_t, LegacyMask, media::AudioDirectMode, audio_direct_mode_t>(
+ legacyMask, legacy2aidl_audio_direct_mode_t_AudioDirectMode,
+ indexToEnum_bitmask<audio_direct_mode_t>,
+ enumToMask_index<int32_t, media::AudioDirectMode>);
+}
+
} // namespace android
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index 7e180a2..be39527 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -41,7 +41,7 @@
},
}
-cc_library_shared {
+cc_library {
name: "libaudiopolicy",
srcs: [
"AudioAttributes.cpp",
@@ -205,7 +205,7 @@
],
apex_available: [
"//apex_available:platform",
- "com.android.bluetooth.updatable",
+ "com.android.bluetooth",
"com.android.media",
"com.android.media.swcodec",
],
@@ -314,6 +314,7 @@
srcs: [
"aidl/android/media/AudioAttributesInternal.aidl",
"aidl/android/media/AudioClient.aidl",
+ "aidl/android/media/AudioDirectMode.aidl",
"aidl/android/media/AudioDualMonoMode.aidl",
"aidl/android/media/AudioFlag.aidl",
"aidl/android/media/AudioGainSys.aidl",
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index 5924d55..edcb86a 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -20,6 +20,7 @@
#include <inttypes.h>
#include <android-base/macros.h>
+#include <android-base/stringprintf.h>
#include <sys/resource.h>
#include <audio_utils/format.h>
@@ -40,6 +41,7 @@
namespace android {
+using ::android::base::StringPrintf;
using android::content::AttributionSourceState;
using aidl_utils::statusTFromBinderStatus;
@@ -67,8 +69,9 @@
// We double the size of input buffer for ping pong use of record buffer.
// Assumes audio_is_linear_pcm(format)
- if ((*frameCount = (size * 2) / (audio_channel_count_from_in_mask(channelMask) *
- audio_bytes_per_sample(format))) == 0) {
+ const auto sampleSize = audio_channel_count_from_in_mask(channelMask) *
+ audio_bytes_per_sample(format);
+ if (sampleSize == 0 || ((*frameCount = (size * 2) / sampleSize) == 0)) {
ALOGE("%s(): Unsupported configuration: sampleRate %u, format %#x, channelMask %#x",
__func__, sampleRate, format, channelMask);
return BAD_VALUE;
@@ -243,11 +246,13 @@
mAudioRecordThread->requestExitAndWait();
mAudioRecordThread.clear();
}
- // No lock here: worst case we remove a NULL callback which will be a nop
+
+ AutoMutex lock(mLock);
if (mDeviceCallback != 0 && mInput != AUDIO_IO_HANDLE_NONE) {
// This may not stop all of these device callbacks!
// TODO: Add some sort of protection.
AudioSystem::removeAudioDeviceCallback(this, mInput, mPortId);
+ mDeviceCallback.clear();
}
}
namespace {
@@ -302,7 +307,6 @@
int32_t maxSharedAudioHistoryMs)
{
status_t status = NO_ERROR;
- uint32_t channelCount;
const sp<IAudioRecordCallback> callbackHandle = callback.promote();
// 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, "
@@ -334,38 +338,8 @@
mSelectedMicFieldDimension = microphoneFieldDimension;
mMaxSharedAudioHistoryMs = maxSharedAudioHistoryMs;
- switch (transferType) {
- case TRANSFER_DEFAULT:
- if (callbackHandle == nullptr || threadCanCallJava) {
- transferType = TRANSFER_SYNC;
- } else {
- transferType = TRANSFER_CALLBACK;
- }
- break;
- case TRANSFER_CALLBACK:
- if (callbackHandle == nullptr) {
- ALOGE("%s(): Transfer type TRANSFER_CALLBACK but callback == nullptr", __func__);
- status = BAD_VALUE;
- goto exit;
- }
- break;
- case TRANSFER_OBTAIN:
- case TRANSFER_SYNC:
- break;
- default:
- ALOGE("%s(): Invalid transfer type %d", __func__, transferType);
- status = BAD_VALUE;
- goto exit;
- }
- mTransfer = transferType;
-
- // invariant that mAudioRecord != 0 is true only after set() returns successfully
- if (mAudioRecord != 0) {
- ALOGE("%s(): Track already in use", __func__);
- status = INVALID_OPERATION;
- goto exit;
- }
-
+ std::string errorMessage;
+ // Copy the state variables early so they are available for error reporting.
if (pAttributes == nullptr) {
mAttributes = AUDIO_ATTRIBUTES_INITIALIZER;
mAttributes.source = inputSource;
@@ -377,37 +351,74 @@
} else {
// stream type shouldn't be looked at, this track has audio attributes
memcpy(&mAttributes, pAttributes, sizeof(audio_attributes_t));
- ALOGV("%s(): Building AudioRecord with attributes: source=%d flags=0x%x tags=[%s]",
+ ALOGV("%s: Building AudioRecord with attributes: source=%d flags=0x%x tags=[%s]",
__func__, mAttributes.source, mAttributes.flags, mAttributes.tags);
}
-
mSampleRate = sampleRate;
-
- // these below should probably come from the audioFlinger too...
if (format == AUDIO_FORMAT_DEFAULT) {
format = AUDIO_FORMAT_PCM_16_BIT;
}
-
- // validate parameters
- // AudioFlinger capture only supports linear PCM
- if (!audio_is_valid_format(format) || !audio_is_linear_pcm(format)) {
- ALOGE("%s(): Format %#x is not linear pcm", __func__, format);
- status = BAD_VALUE;
- goto exit;
+ if (!audio_is_linear_pcm(format)) {
+ // Compressed capture requires direct
+ flags = (audio_input_flags_t) (flags | AUDIO_INPUT_FLAG_DIRECT);
+ ALOGI("%s(): Format %#x is not linear pcm. Setting DIRECT, using flags %#x", __func__,
+ format, flags);
}
mFormat = format;
-
- if (!audio_is_input_channel(channelMask)) {
- ALOGE("%s(): Invalid channel mask %#x", __func__, channelMask);
- status = BAD_VALUE;
- goto exit;
- }
mChannelMask = channelMask;
- channelCount = audio_channel_count_from_in_mask(channelMask);
- mChannelCount = channelCount;
+ mSessionId = sessionId;
+ ALOGV("%s: mSessionId %d", __func__, mSessionId);
+ mOrigFlags = mFlags = flags;
- if (audio_is_linear_pcm(format)) {
- mFrameSize = channelCount * audio_bytes_per_sample(format);
+ mTransfer = transferType;
+ switch (mTransfer) {
+ case TRANSFER_DEFAULT:
+ if (callbackHandle == nullptr || threadCanCallJava) {
+ mTransfer = TRANSFER_SYNC;
+ } else {
+ mTransfer = TRANSFER_CALLBACK;
+ }
+ break;
+ case TRANSFER_CALLBACK:
+ if (callbackHandle == nullptr) {
+ errorMessage = StringPrintf(
+ "%s: Transfer type TRANSFER_CALLBACK but callback == nullptr", __func__);
+ status = BAD_VALUE;
+ goto error;
+ }
+ break;
+ case TRANSFER_OBTAIN:
+ case TRANSFER_SYNC:
+ break;
+ default:
+ errorMessage = StringPrintf("%s: Invalid transfer type %d", __func__, mTransfer);
+ status = BAD_VALUE;
+ goto error;
+ }
+
+ // invariant that mAudioRecord != 0 is true only after set() returns successfully
+ if (mAudioRecord != 0) {
+ errorMessage = StringPrintf("%s: Track already in use", __func__);
+ status = INVALID_OPERATION;
+ goto error;
+ }
+
+ if (!audio_is_valid_format(mFormat)) {
+ errorMessage = StringPrintf("%s: Format %#x is not valid", __func__, mFormat);
+ status = BAD_VALUE;
+ goto error;
+ }
+
+ if (!audio_is_input_channel(mChannelMask)) {
+ errorMessage = StringPrintf("%s: Invalid channel mask %#x", __func__, mChannelMask);
+ status = BAD_VALUE;
+ goto error;
+ }
+
+ mChannelCount = audio_channel_count_from_in_mask(mChannelMask);
+
+ if (audio_is_linear_pcm(mFormat)) {
+ mFrameSize = mChannelCount * audio_bytes_per_sample(mFormat);
} else {
mFrameSize = sizeof(uint8_t);
}
@@ -418,12 +429,7 @@
mNotificationFramesReq = notificationFrames;
// mNotificationFramesAct is initialized in createRecord_l
- mSessionId = sessionId;
- ALOGV("%s(): mSessionId %d", __func__, mSessionId);
-
- mOrigFlags = mFlags = flags;
mCallback = callbackHandle;
-
if (mCallback != nullptr) {
mAudioRecordThread = new AudioRecordThread(*this);
mAudioRecordThread->run("AudioRecord", ANDROID_PRIORITY_AUDIO);
@@ -444,6 +450,7 @@
mAudioRecordThread->requestExitAndWait();
mAudioRecordThread.clear();
}
+ // bypass error message to avoid logging twice (createRecord_l logs the error).
goto exit;
}
@@ -460,11 +467,14 @@
mFramesRead = 0;
mFramesReadServerOffset = 0;
-exit:
- mStatus = status;
+error:
if (status != NO_ERROR) {
mMediaMetrics.markError(status, __FUNCTION__);
+ ALOGE_IF(!errorMessage.empty(), "%s", errorMessage.c_str());
+ reportError(status, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE, errorMessage.c_str());
}
+exit:
+ mStatus = status;
return status;
}
@@ -714,6 +724,11 @@
if (status == OK) {
timestamp->mPosition[ExtendedTimestamp::LOCATION_CLIENT] = mFramesRead;
timestamp->mTimeNs[ExtendedTimestamp::LOCATION_CLIENT] = 0;
+ if (!audio_is_linear_pcm(mFormat)) {
+ // Don't do retrograde corrections or server offset if track is
+ // compressed
+ return OK;
+ }
// server side frame offset in case AudioRecord has been restored.
for (int i = ExtendedTimestamp::LOCATION_SERVER;
i < ExtendedTimestamp::LOCATION_MAX; ++i) {
@@ -855,9 +870,10 @@
status_t status;
static const int32_t kMaxCreateAttempts = 3;
int32_t remainingAttempts = kMaxCreateAttempts;
+ std::string errorMessage;
if (audioFlinger == 0) {
- ALOGE("%s(%d): Could not get audioflinger", __func__, mPortId);
+ errorMessage = StringPrintf("%s(%d): Could not get audioflinger", __func__, mPortId);
status = NO_INIT;
goto exit;
}
@@ -923,8 +939,9 @@
break;
}
if (status != FAILED_TRANSACTION || --remainingAttempts <= 0) {
- ALOGE("%s(%d): AudioFlinger could not create record track, status: %d",
- __func__, mPortId, status);
+ errorMessage = StringPrintf(
+ "%s(%d): AudioFlinger could not create record track, status: %d",
+ __func__, mPortId, status);
goto exit;
}
// FAILED_TRANSACTION happens under very specific conditions causing a state mismatch
@@ -957,7 +974,7 @@
mServerSampleSize = audio_bytes_per_sample(mServerConfig.format);
if (output.cblk == 0) {
- ALOGE("%s(%d): Could not get control block", __func__, mPortId);
+ errorMessage = StringPrintf("%s(%d): Could not get control block", __func__, mPortId);
status = NO_INIT;
goto exit;
}
@@ -967,7 +984,8 @@
// issue (e.g. by copying).
iMemPointer = output.cblk ->unsecurePointer();
if (iMemPointer == NULL) {
- ALOGE("%s(%d): Could not get control block pointer", __func__, mPortId);
+ errorMessage = StringPrintf(
+ "%s(%d): Could not get control block pointer", __func__, mPortId);
status = NO_INIT;
goto exit;
}
@@ -986,7 +1004,8 @@
// issue (e.g. by copying).
buffers = output.buffers->unsecurePointer();
if (buffers == NULL) {
- ALOGE("%s(%d): Could not get buffer pointer", __func__, mPortId);
+ errorMessage = StringPrintf(
+ "%s(%d): Could not get buffer pointer", __func__, mPortId);
status = NO_INIT;
goto exit;
}
@@ -1075,16 +1094,44 @@
.set(AMEDIAMETRICS_PROP_SAMPLERATE, (int32_t)mSampleRate)
// the following are NOT immutable
.set(AMEDIAMETRICS_PROP_STATE, stateToString(mActive))
+ .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)status)
.set(AMEDIAMETRICS_PROP_SELECTEDMICDIRECTION, (int32_t)mSelectedMicDirection)
.set(AMEDIAMETRICS_PROP_SELECTEDMICFIELDDIRECTION, (double)mSelectedMicFieldDimension)
.record();
exit:
+ if (status != NO_ERROR) {
+ ALOGE_IF(!errorMessage.empty(), "%s", errorMessage.c_str());
+ reportError(status, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE, errorMessage.c_str());
+ }
+
mStatus = status;
// sp<IAudioTrack> track destructor will cause releaseOutput() to be called by AudioFlinger
return status;
}
+// Report error associated with the event and some configuration details.
+void AudioRecord::reportError(status_t status, const char *event, const char *message) const
+{
+ if (status == NO_ERROR) return;
+ // We report error on the native side because some callers do not come
+ // from Java.
+ // Ensure these variables are initialized in set().
+ mediametrics::LogItem(AMEDIAMETRICS_KEY_AUDIO_RECORD_ERROR)
+ .set(AMEDIAMETRICS_PROP_EVENT, event)
+ .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)status)
+ .set(AMEDIAMETRICS_PROP_STATUSMESSAGE, message)
+ .set(AMEDIAMETRICS_PROP_ORIGINALFLAGS, toString(mOrigFlags).c_str())
+ .set(AMEDIAMETRICS_PROP_SESSIONID, (int32_t)mSessionId)
+ .set(AMEDIAMETRICS_PROP_SOURCE, toString(mAttributes.source).c_str())
+ .set(AMEDIAMETRICS_PROP_SELECTEDDEVICEID, (int32_t)mSelectedDeviceId)
+ .set(AMEDIAMETRICS_PROP_ENCODING, toString(mFormat).c_str())
+ .set(AMEDIAMETRICS_PROP_CHANNELMASK, (int32_t)mChannelMask)
+ .set(AMEDIAMETRICS_PROP_FRAMECOUNT, (int32_t)mFrameCount)
+ .set(AMEDIAMETRICS_PROP_SAMPLERATE, (int32_t)mSampleRate)
+ .record();
+}
+
status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount, size_t *nonContig)
{
if (audioBuffer == NULL) {
@@ -1148,7 +1195,13 @@
if (status == DEAD_OBJECT) {
// re-create track, unless someone else has already done so
if (newSequence == oldSequence) {
- status = restoreRecord_l("obtainBuffer");
+ if (!audio_is_linear_pcm(mFormat)) {
+ // If compressed capture, don't attempt to restore the track.
+ // Return a DEAD_OBJECT error and let the caller recreate.
+ tryCounter = 0;
+ } else {
+ status = restoreRecord_l("obtainBuffer");
+ }
if (status != NO_ERROR) {
buffer.mFrameCount = 0;
buffer.mRaw = NULL;
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 07ef246..b3c82787 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -2289,6 +2289,31 @@
return OK;
}
+status_t AudioSystem::getDirectPlaybackSupport(const audio_attributes_t *attr,
+ const audio_config_t *config,
+ audio_direct_mode_t* directMode) {
+ if (attr == nullptr || config == nullptr || directMode == nullptr) {
+ return BAD_VALUE;
+ }
+
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) {
+ return PERMISSION_DENIED;
+ }
+
+ media::AudioAttributesInternal attrAidl = VALUE_OR_RETURN_STATUS(
+ legacy2aidl_audio_attributes_t_AudioAttributesInternal(*attr));
+ AudioConfig configAidl = VALUE_OR_RETURN_STATUS(
+ legacy2aidl_audio_config_t_AudioConfig(*config, false /*isInput*/));
+
+ media::AudioDirectMode retAidl;
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
+ aps->getDirectPlaybackSupport(attrAidl, configAidl, &retAidl)));
+ *directMode = VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_audio_direct_mode_t_mask(
+ static_cast<int32_t>(retAidl)));
+ return NO_ERROR;
+}
+
class CaptureStateListenerImpl : public media::BnCaptureStateListener,
public IBinder::DeathRecipient {
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 407b294..de14e1c 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -199,6 +199,7 @@
#define MM_PREFIX "android.media.audiotrack." // avoid cut-n-paste errors.
+ // Do not change this without changing the MediaMetricsService side.
// Java API 28 entries, do not change.
mMetricsItem->setCString(MM_PREFIX "streamtype", toString(track->streamType()).c_str());
mMetricsItem->setCString(MM_PREFIX "type",
@@ -214,6 +215,7 @@
mMetricsItem->setInt32(MM_PREFIX "frameCount", (int32_t)track->mFrameCount);
mMetricsItem->setCString(MM_PREFIX "attributes", toString(track->mAttributes).c_str());
mMetricsItem->setCString(MM_PREFIX "logSessionId", track->mLogSessionId.c_str());
+ mMetricsItem->setInt32(MM_PREFIX "underrunFrames", (int32_t)track->getUnderrunFrames());
}
// hand the user a snapshot of the metrics.
@@ -474,7 +476,8 @@
mAudioTrackThread->requestExitAndWait();
mAudioTrackThread.clear();
}
- // No lock here: worst case we remove a NULL callback which will be a nop
+
+ AutoMutex lock(mLock);
if (mDeviceCallback != 0 && mOutput != AUDIO_IO_HANDLE_NONE) {
// This may not stop all of these device callbacks!
// TODO: Add some sort of protection.
@@ -550,8 +553,54 @@
sessionId, transferType, attributionSource.uid, attributionSource.pid);
mThreadCanCallJava = threadCanCallJava;
+
+ // These variables are pulled in an error report, so we initialize them early.
mSelectedDeviceId = selectedDeviceId;
mSessionId = sessionId;
+ mChannelMask = channelMask;
+ mReqFrameCount = mFrameCount = frameCount;
+ mSampleRate = sampleRate;
+ mOriginalSampleRate = sampleRate;
+ mAttributes = pAttributes != nullptr ? *pAttributes : AUDIO_ATTRIBUTES_INITIALIZER;
+ mPlaybackRate = AUDIO_PLAYBACK_RATE_DEFAULT;
+
+ // update format and flags before storing them in mFormat, mOrigFlags and mFlags
+ if (pAttributes != NULL) {
+ // stream type shouldn't be looked at, this track has audio attributes
+ ALOGV("%s(): Building AudioTrack with attributes:"
+ " usage=%d content=%d flags=0x%x tags=[%s]",
+ __func__,
+ mAttributes.usage, mAttributes.content_type, mAttributes.flags, mAttributes.tags);
+ audio_flags_to_audio_output_flags(mAttributes.flags, &flags);
+ }
+
+ // these below should probably come from the audioFlinger too...
+ if (format == AUDIO_FORMAT_DEFAULT) {
+ format = AUDIO_FORMAT_PCM_16_BIT;
+ } else if (format == AUDIO_FORMAT_IEC61937) { // HDMI pass-through?
+ flags = static_cast<audio_output_flags_t>(flags | AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO);
+ }
+
+ // force direct flag if format is not linear PCM
+ // or offload was requested
+ if ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)
+ || !audio_is_linear_pcm(format)) {
+ ALOGV( (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)
+ ? "%s(): Offload request, forcing to Direct Output"
+ : "%s(): Not linear PCM, forcing to Direct Output",
+ __func__);
+ flags = (audio_output_flags_t)
+ // FIXME why can't we allow direct AND fast?
+ ((flags | AUDIO_OUTPUT_FLAG_DIRECT) & ~AUDIO_OUTPUT_FLAG_FAST);
+ }
+
+ // force direct flag if HW A/V sync requested
+ if ((flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC) != 0) {
+ flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_DIRECT);
+ }
+
+ mFormat = format;
+ mOrigFlags = mFlags = flags;
switch (transferType) {
case TRANSFER_DEFAULT:
@@ -602,9 +651,6 @@
ALOGV_IF(sharedBuffer != 0, "%s(): sharedBuffer: %p, size: %zu",
__func__, sharedBuffer->unsecurePointer(), sharedBuffer->size());
- ALOGV("%s(): streamType %d frameCount %zu flags %04x",
- __func__, streamType, frameCount, flags);
-
// invariant that mAudioTrack != 0 is true only after set() returns successfully
if (mAudioTrack != 0) {
errorMessage = StringPrintf("%s: Track already in use", __func__);
@@ -623,23 +669,8 @@
goto error;
}
mOriginalStreamType = streamType;
-
} else {
- // stream type shouldn't be looked at, this track has audio attributes
- memcpy(&mAttributes, pAttributes, sizeof(audio_attributes_t));
- ALOGV("%s(): Building AudioTrack with attributes:"
- " usage=%d content=%d flags=0x%x tags=[%s]",
- __func__,
- mAttributes.usage, mAttributes.content_type, mAttributes.flags, mAttributes.tags);
mOriginalStreamType = AUDIO_STREAM_DEFAULT;
- audio_flags_to_audio_output_flags(mAttributes.flags, &flags);
- }
-
- // these below should probably come from the audioFlinger too...
- if (format == AUDIO_FORMAT_DEFAULT) {
- format = AUDIO_FORMAT_PCM_16_BIT;
- } else if (format == AUDIO_FORMAT_IEC61937) { // HDMI pass-through?
- flags = static_cast<audio_output_flags_t>(flags | AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO);
}
// validate parameters
@@ -648,36 +679,16 @@
status = BAD_VALUE;
goto error;
}
- mFormat = format;
if (!audio_is_output_channel(channelMask)) {
errorMessage = StringPrintf("%s: Invalid channel mask %#x", __func__, channelMask);
status = BAD_VALUE;
goto error;
}
- mChannelMask = channelMask;
channelCount = audio_channel_count_from_out_mask(channelMask);
mChannelCount = channelCount;
- // force direct flag if format is not linear PCM
- // or offload was requested
- if ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)
- || !audio_is_linear_pcm(format)) {
- ALOGV( (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)
- ? "%s(): Offload request, forcing to Direct Output"
- : "%s(): Not linear PCM, forcing to Direct Output",
- __func__);
- flags = (audio_output_flags_t)
- // FIXME why can't we allow direct AND fast?
- ((flags | AUDIO_OUTPUT_FLAG_DIRECT) & ~AUDIO_OUTPUT_FLAG_FAST);
- }
-
- // force direct flag if HW A/V sync requested
- if ((flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC) != 0) {
- flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_DIRECT);
- }
-
- if (flags & AUDIO_OUTPUT_FLAG_DIRECT) {
+ if (mFlags & AUDIO_OUTPUT_FLAG_DIRECT) {
if (audio_has_proportional_frames(format)) {
mFrameSize = channelCount * audio_bytes_per_sample(format);
} else {
@@ -691,15 +702,12 @@
}
// sampling rate must be specified for direct outputs
- if (sampleRate == 0 && (flags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
+ if (sampleRate == 0 && (mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
errorMessage = StringPrintf(
"%s: sample rate must be specified for direct outputs", __func__);
status = BAD_VALUE;
goto error;
}
- mSampleRate = sampleRate;
- mOriginalSampleRate = sampleRate;
- mPlaybackRate = AUDIO_PLAYBACK_RATE_DEFAULT;
// 1.0 <= mMaxRequiredSpeed <= AUDIO_TIMESTRETCH_SPEED_MAX
mMaxRequiredSpeed = min(max(maxRequiredSpeed, 1.0f), AUDIO_TIMESTRETCH_SPEED_MAX);
@@ -719,12 +727,11 @@
mVolume[AUDIO_INTERLEAVE_RIGHT] = 1.0f;
mSendLevel = 0.0f;
// mFrameCount is initialized in createTrack_l
- mReqFrameCount = frameCount;
if (notificationFrames >= 0) {
mNotificationFramesReq = notificationFrames;
mNotificationsPerBufferReq = 0;
} else {
- if (!(flags & AUDIO_OUTPUT_FLAG_FAST)) {
+ if (!(mFlags & AUDIO_OUTPUT_FLAG_FAST)) {
errorMessage = StringPrintf(
"%s: notificationFrames=%d not permitted for non-fast track",
__func__, notificationFrames);
@@ -760,7 +767,6 @@
mClientAttributionSource.pid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(callingPid));
}
mAuxEffectId = 0;
- mOrigFlags = mFlags = flags;
mCallback = callback;
if (_callback != nullptr) {
@@ -1114,8 +1120,16 @@
{
using namespace std::chrono_literals;
+ // We use atomic access here for state variables - these are used as hints
+ // to ensure we have ramped down audio.
+ const int priorState = mProxy->getState();
+ const uint32_t priorPosition = mProxy->getPosition().unsignedValue();
+
pause();
+ // Only if we were previously active, do we wait to ramp down the audio.
+ if (priorState != CBLK_STATE_ACTIVE) return true;
+
AutoMutex lock(mLock);
// offload and direct tracks do not wait because pause volume ramp is handled by hardware.
if (isOffloadedOrDirect_l()) return true;
@@ -1123,16 +1137,25 @@
// Wait for the track state to be anything besides pausing.
// This ensures that the volume has ramped down.
constexpr auto SLEEP_INTERVAL_MS = 10ms;
+ constexpr auto POSITION_TIMEOUT_MS = 40ms; // don't wait longer than this for position change.
auto begin = std::chrono::steady_clock::now();
while (true) {
- // wait for state to change
+ // Wait for state and position to change.
+ // After pause() the server state should be PAUSING, but that may immediately
+ // convert to PAUSED by prepareTracks before data is read into the mixer.
+ // Hence we check that the state is not PAUSING and that the server position
+ // has advanced to be a more reliable estimate that the volume ramp has completed.
const int state = mProxy->getState();
+ const uint32_t position = mProxy->getPosition().unsignedValue();
mLock.unlock(); // only local variables accessed until lock.
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - begin);
- if (state != CBLK_STATE_PAUSING) {
- ALOGV("%s: success state:%d after %lld ms", __func__, state, elapsed.count());
+ if (state != CBLK_STATE_PAUSING &&
+ (elapsed >= POSITION_TIMEOUT_MS || position != priorPosition)) {
+ ALOGV("%s: success state:%d, position:%u after %lld ms"
+ " (prior state:%d prior position:%u)",
+ __func__, state, position, elapsed.count(), priorState, priorPosition);
return true;
}
std::chrono::milliseconds remaining = timeout - elapsed;
@@ -2116,6 +2139,7 @@
.set(AMEDIAMETRICS_PROP_VOLUME_LEFT, (double)mVolume[AUDIO_INTERLEAVE_LEFT])
.set(AMEDIAMETRICS_PROP_VOLUME_RIGHT, (double)mVolume[AUDIO_INTERLEAVE_RIGHT])
.set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
+ .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)NO_ERROR)
.set(AMEDIAMETRICS_PROP_AUXEFFECTID, (int32_t)mAuxEffectId)
.set(AMEDIAMETRICS_PROP_SAMPLERATE, (int32_t)mSampleRate)
.set(AMEDIAMETRICS_PROP_PLAYBACK_SPEED, (double)mPlaybackRate.mSpeed)
@@ -2155,10 +2179,11 @@
if (status == NO_ERROR) return;
// We report error on the native side because some callers do not come
// from Java.
- mediametrics::LogItem(std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK) + "error")
+ // Ensure these variables are initialized in set().
+ mediametrics::LogItem(AMEDIAMETRICS_KEY_AUDIO_TRACK_ERROR)
.set(AMEDIAMETRICS_PROP_EVENT, event)
- .set(AMEDIAMETRICS_PROP_ERROR, mediametrics::statusToErrorString(status))
- .set(AMEDIAMETRICS_PROP_ERRORMESSAGE, message)
+ .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)status)
+ .set(AMEDIAMETRICS_PROP_STATUSMESSAGE, message)
.set(AMEDIAMETRICS_PROP_ORIGINALFLAGS, toString(mOrigFlags).c_str())
.set(AMEDIAMETRICS_PROP_SESSIONID, (int32_t)mSessionId)
.set(AMEDIAMETRICS_PROP_CONTENTTYPE, toString(mAttributes.content_type).c_str())
@@ -2166,8 +2191,10 @@
.set(AMEDIAMETRICS_PROP_SELECTEDDEVICEID, (int32_t)mSelectedDeviceId)
.set(AMEDIAMETRICS_PROP_ENCODING, toString(mFormat).c_str())
.set(AMEDIAMETRICS_PROP_CHANNELMASK, (int32_t)mChannelMask)
- .set(AMEDIAMETRICS_PROP_FRAMECOUNT, (int32_t)mReqFrameCount) // requested frame count
// the following are NOT immutable
+ // frame count is initially the requested frame count, but may be adjusted
+ // by AudioFlinger after creation.
+ .set(AMEDIAMETRICS_PROP_FRAMECOUNT, (int32_t)mFrameCount)
.set(AMEDIAMETRICS_PROP_SAMPLERATE, (int32_t)mSampleRate)
.set(AMEDIAMETRICS_PROP_PLAYBACK_SPEED, (double)mPlaybackRate.mSpeed)
.set(AMEDIAMETRICS_PROP_PLAYBACK_PITCH, (double)mPlaybackRate.mPitch)
diff --git a/media/libaudioclient/AudioTrackShared.cpp b/media/libaudioclient/AudioTrackShared.cpp
index 35719be..e3b79b2 100644
--- a/media/libaudioclient/AudioTrackShared.cpp
+++ b/media/libaudioclient/AudioTrackShared.cpp
@@ -409,7 +409,7 @@
android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
// it seems that a FUTEX_WAKE_PRIVATE will not wake a FUTEX_WAIT, even within same process
(void) syscall(__NR_futex, &cblk->mFutex, mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE,
- 1);
+ INT_MAX);
}
}
@@ -419,7 +419,7 @@
if (!(android_atomic_or(CBLK_INTERRUPT, &cblk->mFlags) & CBLK_INTERRUPT)) {
android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
(void) syscall(__NR_futex, &cblk->mFutex, mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE,
- 1);
+ INT_MAX);
}
}
@@ -490,6 +490,8 @@
status_t AudioTrackClientProxy::waitStreamEndDone(const struct timespec *requested)
{
struct timespec total; // total elapsed time spent waiting
+ struct timespec before;
+ bool beforeIsValid = false;
total.tv_sec = 0;
total.tv_nsec = 0;
audio_track_cblk_t* cblk = mCblk;
@@ -570,17 +572,38 @@
}
int32_t old = android_atomic_and(~CBLK_FUTEX_WAKE, &cblk->mFutex);
if (!(old & CBLK_FUTEX_WAKE)) {
+ if (!beforeIsValid) {
+ clock_gettime(CLOCK_MONOTONIC, &before);
+ beforeIsValid = true;
+ }
errno = 0;
(void) syscall(__NR_futex, &cblk->mFutex,
mClientInServer ? FUTEX_WAIT_PRIVATE : FUTEX_WAIT, old & ~CBLK_FUTEX_WAKE, ts);
- switch (errno) {
+ status_t error = errno; // clock_gettime can affect errno
+ {
+ struct timespec after;
+ clock_gettime(CLOCK_MONOTONIC, &after);
+ total.tv_sec += after.tv_sec - before.tv_sec;
+ // Use auto instead of long to avoid the google-runtime-int warning.
+ auto deltaNs = after.tv_nsec - before.tv_nsec;
+ if (deltaNs < 0) {
+ deltaNs += 1000000000;
+ total.tv_sec--;
+ }
+ if ((total.tv_nsec += deltaNs) >= 1000000000) {
+ total.tv_nsec -= 1000000000;
+ total.tv_sec++;
+ }
+ before = after;
+ }
+ switch (error) {
case 0: // normal wakeup by server, or by binderDied()
case EWOULDBLOCK: // benign race condition with server
case EINTR: // wait was interrupted by signal or other spurious wakeup
case ETIMEDOUT: // time-out expired
break;
default:
- status = errno;
+ status = error;
ALOGE("%s unexpected error %s", __func__, strerror(status));
goto end;
}
@@ -747,7 +770,7 @@
int32_t old = android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
if (!(old & CBLK_FUTEX_WAKE)) {
(void) syscall(__NR_futex, &cblk->mFutex,
- mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE, 1);
+ mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE, INT_MAX);
}
}
mFlushed += (newFront - front) & mask;
@@ -917,7 +940,7 @@
int32_t old = android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
if (!(old & CBLK_FUTEX_WAKE)) {
(void) syscall(__NR_futex, &cblk->mFutex,
- mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE, 1);
+ mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE, INT_MAX);
}
}
diff --git a/media/libaudioclient/aidl/android/media/AudioDirectMode.aidl b/media/libaudioclient/aidl/android/media/AudioDirectMode.aidl
new file mode 100644
index 0000000..0da4721
--- /dev/null
+++ b/media/libaudioclient/aidl/android/media/AudioDirectMode.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media;
+
+@Backing(type="int")
+enum AudioDirectMode {
+ NONE = 0,
+ OFFLOAD = 1,
+ OFFLOAD_GAPLESS = 2,
+ BITSTREAM = 4,
+}
diff --git a/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl b/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
index 8e9ff86..7895ae3 100644
--- a/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
@@ -20,6 +20,7 @@
import android.media.AudioAttributesEx;
import android.media.AudioAttributesInternal;
+import android.media.AudioDirectMode;
import android.media.AudioMix;
import android.media.AudioOffloadMode;
import android.media.AudioPatch;
@@ -376,4 +377,10 @@
boolean canBeSpatialized(in @nullable AudioAttributesInternal attr,
in @nullable AudioConfig config,
in AudioDevice[] devices);
+
+ /**
+ * Query how the direct playback is currently supported on the device.
+ */
+ AudioDirectMode getDirectPlaybackSupport(in AudioAttributesInternal attr,
+ in AudioConfig config);
}
diff --git a/media/libaudioclient/include/media/AidlConversion.h b/media/libaudioclient/include/media/AidlConversion.h
index a6c93cf..e769303 100644
--- a/media/libaudioclient/include/media/AidlConversion.h
+++ b/media/libaudioclient/include/media/AidlConversion.h
@@ -23,6 +23,7 @@
#include <android/media/AudioAttributesInternal.h>
#include <android/media/AudioClient.h>
+#include <android/media/AudioDirectMode.h>
#include <android/media/AudioDualMonoMode.h>
#include <android/media/AudioFlag.h>
#include <android/media/AudioIoConfigEvent.h>
@@ -445,5 +446,13 @@
legacy2aidl_TrackSecondaryOutputInfoPair_TrackSecondaryOutputInfo(
const TrackSecondaryOutputInfoPair& legacy);
+ConversionResult<audio_direct_mode_t>
+aidl2legacy_AudioDirectMode_audio_direct_mode_t(media::AudioDirectMode aidl);
+ConversionResult<media::AudioDirectMode>
+legacy2aidl_audio_direct_mode_t_AudioDirectMode(audio_direct_mode_t legacy);
+
+ConversionResult<audio_direct_mode_t> aidl2legacy_int32_t_audio_direct_mode_t_mask(int32_t aidl);
+ConversionResult<int32_t> legacy2aidl_audio_direct_mode_t_int32_t_mask(audio_direct_mode_t legacy);
+
} // namespace android
diff --git a/media/libaudioclient/include/media/AudioRecord.h b/media/libaudioclient/include/media/AudioRecord.h
index f6faaae..3cfcbf3 100644
--- a/media/libaudioclient/include/media/AudioRecord.h
+++ b/media/libaudioclient/include/media/AudioRecord.h
@@ -890,6 +890,8 @@
MediaMetrics mMediaMetrics;
std::string mMetricsId; // GUARDED_BY(mLock), could change in createRecord_l().
std::string mCallerName; // for example "aaudio"
+
+ void reportError(status_t status, const char *event, const char *message) const;
};
}; // namespace android
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 0e9d48c..11eb070 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -536,6 +536,19 @@
const AudioDeviceTypeAddrVector &devices,
bool *canBeSpatialized);
+ /**
+ * Query how the direct playback is currently supported on the device.
+ * @param attr audio attributes describing the playback use case
+ * @param config audio configuration for the playback
+ * @param directMode out: a set of flags describing how the direct playback is currently
+ * supported on the device
+ * @return NO_ERROR in case of success, DEAD_OBJECT, NO_INIT, BAD_VALUE, PERMISSION_DENIED
+ * in case of error.
+ */
+ static status_t getDirectPlaybackSupport(const audio_attributes_t *attr,
+ const audio_config_t *config,
+ audio_direct_mode_t *directMode);
+
// A listener for capture state changes.
class CaptureStateListener : public virtual RefBase {
diff --git a/media/libaudiofoundation/AudioContainers.cpp b/media/libaudiofoundation/AudioContainers.cpp
index 117d188..553a319 100644
--- a/media/libaudiofoundation/AudioContainers.cpp
+++ b/media/libaudiofoundation/AudioContainers.cpp
@@ -89,6 +89,11 @@
return ss.str();
}
+bool deviceTypesToString(const DeviceTypeSet &deviceTypes, std::string &str) {
+ str = deviceTypesToString(deviceTypes);
+ return true;
+}
+
std::string dumpDeviceTypes(const DeviceTypeSet &deviceTypes) {
std::stringstream ss;
for (auto it = deviceTypes.begin(); it != deviceTypes.end(); ++it) {
diff --git a/media/libaudiofoundation/include/media/AudioContainers.h b/media/libaudiofoundation/include/media/AudioContainers.h
index 707ab68..a9c7824 100644
--- a/media/libaudiofoundation/include/media/AudioContainers.h
+++ b/media/libaudiofoundation/include/media/AudioContainers.h
@@ -111,28 +111,10 @@
return types;
}
-// FIXME: This is temporary helper function. Remove this when getting rid of all
-// bit mask usages of audio device types.
-static inline DeviceTypeSet deviceTypesFromBitMask(audio_devices_t types) {
- DeviceTypeSet deviceTypes;
- if ((types & AUDIO_DEVICE_BIT_IN) == 0) {
- for (auto deviceType : AUDIO_DEVICE_OUT_ALL_ARRAY) {
- if ((types & deviceType) == deviceType) {
- deviceTypes.insert(deviceType);
- }
- }
- } else {
- for (auto deviceType : AUDIO_DEVICE_IN_ALL_ARRAY) {
- if ((types & deviceType) == deviceType) {
- deviceTypes.insert(deviceType);
- }
- }
- }
- return deviceTypes;
-}
-
std::string deviceTypesToString(const DeviceTypeSet& deviceTypes);
+bool deviceTypesToString(const DeviceTypeSet& deviceTypes, std::string &str);
+
std::string dumpDeviceTypes(const DeviceTypeSet& deviceTypes);
/**
diff --git a/media/libaudiohal/impl/DeviceHalHidl.cpp b/media/libaudiohal/impl/DeviceHalHidl.cpp
index 47acb19..209094c 100644
--- a/media/libaudiohal/impl/DeviceHalHidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalHidl.cpp
@@ -205,6 +205,16 @@
status != OK) {
return status;
}
+
+#if !(MAJOR_VERSION == 7 && MINOR_VERSION == 1)
+ //TODO: b/193496180 use spatializer flag at audio HAL when available
+ if ((flags & AUDIO_OUTPUT_FLAG_SPATIALIZER) != 0) {
+ flags = (audio_output_flags_t)(flags & ~AUDIO_OUTPUT_FLAG_SPATIALIZER);
+ flags = (audio_output_flags_t)
+ (flags | AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_DEEP_BUFFER);
+ }
+#endif
+
CoreUtils::AudioOutputFlags hidlFlags;
if (status_t status = CoreUtils::audioOutputFlagsFromHal(flags, &hidlFlags); status != OK) {
return status;
diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp
index 19a8b2f..61a2bf5 100644
--- a/media/libeffects/preprocessing/PreProcessing.cpp
+++ b/media/libeffects/preprocessing/PreProcessing.cpp
@@ -150,6 +150,7 @@
bool sHasAuxChannels[PREPROC_NUM_EFFECTS] = {
false, // PREPROC_AGC
+ false, // PREPROC_AGC2
true, // PREPROC_AEC
true, // PREPROC_NS
};
diff --git a/media/libheadtracking/Android.bp b/media/libheadtracking/Android.bp
index 63b769e..b0563e2 100644
--- a/media/libheadtracking/Android.bp
+++ b/media/libheadtracking/Android.bp
@@ -18,6 +18,7 @@
"PoseRateLimiter.cpp",
"QuaternionUtil.cpp",
"ScreenHeadFusion.cpp",
+ "StillnessDetector.cpp",
"Twist.cpp",
],
export_include_dirs: [
@@ -70,6 +71,7 @@
"PoseRateLimiter-test.cpp",
"QuaternionUtil-test.cpp",
"ScreenHeadFusion-test.cpp",
+ "StillnessDetector-test.cpp",
"Twist-test.cpp",
],
shared_libs: [
diff --git a/media/libheadtracking/HeadTrackingProcessor.cpp b/media/libheadtracking/HeadTrackingProcessor.cpp
index 47f7cf0..f2f15df 100644
--- a/media/libheadtracking/HeadTrackingProcessor.cpp
+++ b/media/libheadtracking/HeadTrackingProcessor.cpp
@@ -20,6 +20,7 @@
#include "PoseDriftCompensator.h"
#include "QuaternionUtil.h"
#include "ScreenHeadFusion.h"
+#include "StillnessDetector.h"
namespace android {
namespace media {
@@ -40,6 +41,18 @@
.translationalDriftTimeConstant = options.translationalDriftTimeConstant,
.rotationalDriftTimeConstant = options.rotationalDriftTimeConstant,
}),
+ mHeadStillnessDetector(StillnessDetector::Options{
+ .defaultValue = false,
+ .windowDuration = options.autoRecenterWindowDuration,
+ .translationalThreshold = options.autoRecenterTranslationalThreshold,
+ .rotationalThreshold = options.autoRecenterRotationalThreshold,
+ }),
+ mScreenStillnessDetector(StillnessDetector::Options{
+ .defaultValue = true,
+ .windowDuration = options.screenStillnessWindowDuration,
+ .translationalThreshold = options.screenStillnessTranslationalThreshold,
+ .rotationalThreshold = options.screenStillnessRotationalThreshold,
+ }),
mModeSelector(ModeSelector::Options{.freshnessTimeout = options.freshnessTimeout},
initialMode),
mRateLimiter(PoseRateLimiter::Options{
@@ -53,6 +66,7 @@
Pose3f predictedWorldToHead =
worldToHead * integrate(headTwist, mOptions.predictionDuration);
mHeadPoseDriftCompensator.setInput(timestamp, predictedWorldToHead);
+ mHeadStillnessDetector.setInput(timestamp, predictedWorldToHead);
mWorldToHeadTimestamp = timestamp;
}
@@ -63,8 +77,9 @@
mPhysicalToLogicalAngle = mPendingPhysicalToLogicalAngle;
}
- mScreenPoseDriftCompensator.setInput(
- timestamp, worldToScreen * Pose3f(rotateY(-mPhysicalToLogicalAngle)));
+ Pose3f worldToLogicalScreen = worldToScreen * Pose3f(rotateY(-mPhysicalToLogicalAngle));
+ mScreenPoseDriftCompensator.setInput(timestamp, worldToLogicalScreen);
+ mScreenStillnessDetector.setInput(timestamp, worldToLogicalScreen);
mWorldToScreenTimestamp = timestamp;
}
@@ -77,18 +92,32 @@
}
void calculate(int64_t timestamp) override {
- if (mWorldToHeadTimestamp.has_value()) {
- const Pose3f worldToHead = mHeadPoseDriftCompensator.getOutput();
- mScreenHeadFusion.setWorldToHeadPose(mWorldToHeadTimestamp.value(), worldToHead);
- mModeSelector.setWorldToHeadPose(mWorldToHeadTimestamp.value(), worldToHead);
- }
-
+ // Handle the screen first, since it might trigger a recentering of the head.
if (mWorldToScreenTimestamp.has_value()) {
const Pose3f worldToLogicalScreen = mScreenPoseDriftCompensator.getOutput();
+ bool screenStable = mScreenStillnessDetector.calculate(timestamp);
+ mModeSelector.setScreenStable(mWorldToScreenTimestamp.value(), screenStable);
+ // Whenever the screen is unstable, recenter the head pose.
+ if (!screenStable) {
+ recenter(true, false);
+ }
mScreenHeadFusion.setWorldToScreenPose(mWorldToScreenTimestamp.value(),
worldToLogicalScreen);
}
+ // Handle head.
+ if (mWorldToHeadTimestamp.has_value()) {
+ Pose3f worldToHead = mHeadPoseDriftCompensator.getOutput();
+ // Auto-recenter.
+ if (mHeadStillnessDetector.calculate(timestamp)) {
+ recenter(true, false);
+ worldToHead = mHeadPoseDriftCompensator.getOutput();
+ }
+
+ mScreenHeadFusion.setWorldToHeadPose(mWorldToHeadTimestamp.value(), worldToHead);
+ mModeSelector.setWorldToHeadPose(mWorldToHeadTimestamp.value(), worldToHead);
+ }
+
auto maybeScreenToHead = mScreenHeadFusion.calculate();
if (maybeScreenToHead.has_value()) {
mModeSelector.setScreenToHeadPose(maybeScreenToHead->timestamp,
@@ -114,9 +143,11 @@
void recenter(bool recenterHead, bool recenterScreen) override {
if (recenterHead) {
mHeadPoseDriftCompensator.recenter();
+ mHeadStillnessDetector.reset();
}
if (recenterScreen) {
mScreenPoseDriftCompensator.recenter();
+ mScreenStillnessDetector.reset();
}
// If a sensor being recentered is included in the current mode, apply rate limiting to
@@ -140,6 +171,8 @@
Pose3f mHeadToStagePose;
PoseDriftCompensator mHeadPoseDriftCompensator;
PoseDriftCompensator mScreenPoseDriftCompensator;
+ StillnessDetector mHeadStillnessDetector;
+ StillnessDetector mScreenStillnessDetector;
ScreenHeadFusion mScreenHeadFusion;
ModeSelector mModeSelector;
PoseRateLimiter mRateLimiter;
diff --git a/media/libheadtracking/ModeSelector-test.cpp b/media/libheadtracking/ModeSelector-test.cpp
index 6247d84..a136e6b 100644
--- a/media/libheadtracking/ModeSelector-test.cpp
+++ b/media/libheadtracking/ModeSelector-test.cpp
@@ -44,6 +44,7 @@
ModeSelector selector(options, HeadTrackingMode::WORLD_RELATIVE);
selector.setWorldToHeadPose(0, worldToHead);
+ selector.setScreenStable(0, true);
selector.calculate(0);
EXPECT_EQ(HeadTrackingMode::WORLD_RELATIVE, selector.getActualMode());
EXPECT_EQ(selector.getHeadToStagePose(), worldToHead.inverse());
@@ -69,14 +70,46 @@
ModeSelector selector(options);
selector.setScreenToStagePose(screenToStage);
-
selector.setDesiredMode(HeadTrackingMode::WORLD_RELATIVE);
selector.setWorldToHeadPose(0, worldToHead);
+ selector.setScreenStable(0, true);
selector.calculate(0);
EXPECT_EQ(HeadTrackingMode::WORLD_RELATIVE, selector.getActualMode());
EXPECT_EQ(selector.getHeadToStagePose(), worldToHead.inverse() * screenToStage);
}
+TEST(ModeSelector, WorldRelativeUnstable) {
+ const Pose3f worldToHead({1, 2, 3}, Quaternionf::UnitRandom());
+ const Pose3f screenToStage({4, 5, 6}, Quaternionf::UnitRandom());
+
+ ModeSelector::Options options{.freshnessTimeout = 100};
+ ModeSelector selector(options);
+
+ selector.setScreenToStagePose(screenToStage);
+ selector.setDesiredMode(HeadTrackingMode::WORLD_RELATIVE);
+ selector.setWorldToHeadPose(0, worldToHead);
+ selector.setScreenStable(0, false);
+ selector.calculate(10);
+ EXPECT_EQ(HeadTrackingMode::STATIC, selector.getActualMode());
+ EXPECT_EQ(selector.getHeadToStagePose(), screenToStage);
+}
+
+TEST(ModeSelector, WorldRelativeStableStale) {
+ const Pose3f worldToHead({1, 2, 3}, Quaternionf::UnitRandom());
+ const Pose3f screenToStage({4, 5, 6}, Quaternionf::UnitRandom());
+
+ ModeSelector::Options options{.freshnessTimeout = 100};
+ ModeSelector selector(options);
+
+ selector.setScreenToStagePose(screenToStage);
+ selector.setDesiredMode(HeadTrackingMode::WORLD_RELATIVE);
+ selector.setWorldToHeadPose(100, worldToHead);
+ selector.setScreenStable(0, true);
+ selector.calculate(101);
+ EXPECT_EQ(HeadTrackingMode::STATIC, selector.getActualMode());
+ EXPECT_EQ(selector.getHeadToStagePose(), screenToStage);
+}
+
TEST(ModeSelector, WorldRelativeStale) {
const Pose3f worldToHead({1, 2, 3}, Quaternionf::UnitRandom());
const Pose3f screenToStage({4, 5, 6}, Quaternionf::UnitRandom());
@@ -85,7 +118,6 @@
ModeSelector selector(options);
selector.setScreenToStagePose(screenToStage);
-
selector.setDesiredMode(HeadTrackingMode::WORLD_RELATIVE);
selector.setWorldToHeadPose(0, worldToHead);
selector.calculate(101);
@@ -101,7 +133,6 @@
ModeSelector selector(options);
selector.setScreenToStagePose(screenToStage);
-
selector.setDesiredMode(HeadTrackingMode::SCREEN_RELATIVE);
selector.setScreenToHeadPose(0, screenToHead);
selector.calculate(0);
@@ -118,10 +149,10 @@
ModeSelector selector(options);
selector.setScreenToStagePose(screenToStage);
-
selector.setDesiredMode(HeadTrackingMode::SCREEN_RELATIVE);
selector.setScreenToHeadPose(0, screenToHead);
selector.setWorldToHeadPose(50, worldToHead);
+ selector.setScreenStable(50, true);
selector.calculate(101);
EXPECT_EQ(HeadTrackingMode::WORLD_RELATIVE, selector.getActualMode());
EXPECT_EQ(selector.getHeadToStagePose(), worldToHead.inverse() * screenToStage);
@@ -139,6 +170,7 @@
selector.setDesiredMode(HeadTrackingMode::SCREEN_RELATIVE);
selector.setScreenToHeadPose(50, std::nullopt);
selector.setWorldToHeadPose(50, worldToHead);
+ selector.setScreenStable(50, true);
selector.calculate(101);
EXPECT_EQ(HeadTrackingMode::WORLD_RELATIVE, selector.getActualMode());
EXPECT_EQ(selector.getHeadToStagePose(), worldToHead.inverse() * screenToStage);
diff --git a/media/libheadtracking/ModeSelector.cpp b/media/libheadtracking/ModeSelector.cpp
index 16e1712..cb3a27f 100644
--- a/media/libheadtracking/ModeSelector.cpp
+++ b/media/libheadtracking/ModeSelector.cpp
@@ -41,11 +41,18 @@
mWorldToHeadTimestamp = timestamp;
}
+void ModeSelector::setScreenStable(int64_t timestamp, bool stable) {
+ mScreenStable = stable;
+ mScreenStableTimestamp = timestamp;
+}
+
void ModeSelector::calculateActualMode(int64_t timestamp) {
bool isValidScreenToHead = mScreenToHead.has_value() &&
timestamp - mScreenToHeadTimestamp < mOptions.freshnessTimeout;
bool isValidWorldToHead = mWorldToHead.has_value() &&
timestamp - mWorldToHeadTimestamp < mOptions.freshnessTimeout;
+ bool isValidScreenStable = mScreenStable.has_value() &&
+ timestamp - mScreenStableTimestamp < mOptions.freshnessTimeout;
HeadTrackingMode mode = mDesiredMode;
@@ -58,7 +65,7 @@
// Optional downgrade from world-relative to static.
if (mode == HeadTrackingMode::WORLD_RELATIVE) {
- if (!isValidWorldToHead) {
+ if (!isValidWorldToHead || !isValidScreenStable || !mScreenStable.value()) {
mode = HeadTrackingMode::STATIC;
}
}
diff --git a/media/libheadtracking/ModeSelector.h b/media/libheadtracking/ModeSelector.h
index 17a5142..e537040 100644
--- a/media/libheadtracking/ModeSelector.h
+++ b/media/libheadtracking/ModeSelector.h
@@ -56,6 +56,7 @@
* from screen-relative to world-relative.
* - When we cannot get a fresh estimate of the world-to-head pose, we will fall back from
* world-relative to static.
+ * - In world-relative mode, if the screen is unstable, we will fall back to static.
*
* All the timestamps used here are of arbitrary units and origin. They just need to be consistent
* between all the calls and with the Options provided for determining freshness and rate limiting.
@@ -92,6 +93,12 @@
void setWorldToHeadPose(int64_t timestamp, const Pose3f& worldToHead);
/**
+ * Set whether the screen is considered stable.
+ * The timestamp needs to reflect how fresh the sample is.
+ */
+ void setScreenStable(int64_t timestamp, bool stable);
+
+ /**
* Process all the previous inputs and update the outputs.
*/
void calculate(int64_t timestamp);
@@ -116,6 +123,8 @@
int64_t mScreenToHeadTimestamp;
std::optional<Pose3f> mWorldToHead;
int64_t mWorldToHeadTimestamp;
+ std::optional<bool> mScreenStable;
+ int64_t mScreenStableTimestamp;
HeadTrackingMode mActualMode;
Pose3f mHeadToStage;
diff --git a/media/libheadtracking/Pose.cpp b/media/libheadtracking/Pose.cpp
index 47241ce..ae39512 100644
--- a/media/libheadtracking/Pose.cpp
+++ b/media/libheadtracking/Pose.cpp
@@ -43,7 +43,7 @@
return {to, false};
}
// Always rate limit if t is 0 (required to avoid division by 0).
- if (t == 0) {
+ if (t == 0 || maxTranslationalVelocity == 0 || maxRotationalVelocity == 0) {
return {from, true};
}
diff --git a/media/libheadtracking/PoseProcessingGraph.png b/media/libheadtracking/PoseProcessingGraph.png
index 0363068..2b4ea68 100644
--- a/media/libheadtracking/PoseProcessingGraph.png
+++ b/media/libheadtracking/PoseProcessingGraph.png
Binary files differ
diff --git a/media/libheadtracking/README.md b/media/libheadtracking/README.md
index 3d5b71a..5ec157b 100644
--- a/media/libheadtracking/README.md
+++ b/media/libheadtracking/README.md
@@ -157,6 +157,14 @@
module may indicate that the user is likely not in front of the screen via the
“valid” output.
+## Stillness Detector
+
+The stillness detector blocks detect when their incoming pose stream has been
+stable for a given amount of time (allowing for a configurable amount of error).
+When the head is considered still, we would trigger a recenter operation
+(“auto-recentering”) and when the screen is considered not still, the mode
+selector would use this information to force static mode.
+
### Mode Selector
The Mode Selector block aggregates the various sources of pose information into
@@ -168,7 +176,8 @@
- If the desired mode is static, the actual mode is static.
- If the desired mode is world-relative:
- - If head poses are fresh, the actual mode is world-relative.
+ - If head and screen poses are fresh and the screen is stable (stillness
+ detector output is true), the actual mode is world-relative.
- Otherwise the actual mode is static.
- If the desired mode is screen-relative:
- If head and screen poses are fresh and the ‘valid’ signal is asserted, the
diff --git a/media/libheadtracking/SensorPoseProvider.cpp b/media/libheadtracking/SensorPoseProvider.cpp
index ec5e1ec..0e96b03 100644
--- a/media/libheadtracking/SensorPoseProvider.cpp
+++ b/media/libheadtracking/SensorPoseProvider.cpp
@@ -133,14 +133,14 @@
{
std::lock_guard lock(mMutex);
- mEnabledSensorFormats.emplace(sensor, format);
+ mEnabledSensorsExtra.emplace(sensor, SensorExtra{ .format = format });
}
// Enable the sensor.
if (mQueue->enableSensor(sensor, samplingPeriod.count(), 0, 0)) {
ALOGE("Failed to enable sensor");
std::lock_guard lock(mMutex);
- mEnabledSensorFormats.erase(sensor);
+ mEnabledSensorsExtra.erase(sensor);
return false;
}
@@ -151,7 +151,7 @@
void stopSensor(int handle) override {
mEnabledSensors.erase(handle);
std::lock_guard lock(mMutex);
- mEnabledSensorFormats.erase(handle);
+ mEnabledSensorsExtra.erase(handle);
}
private:
@@ -159,6 +159,7 @@
kUnknown,
kQuaternion,
kRotationVectorsAndFlags,
+ kRotationVectorsAndDiscontinuityCount,
};
struct PoseEvent {
@@ -167,13 +168,18 @@
bool isNewReference;
};
+ struct SensorExtra {
+ DataFormat format;
+ std::optional<int32_t> discontinuityCount;
+ };
+
sp<Looper> mLooper;
Listener* const mListener;
SensorManager* const mSensorManager;
std::thread mThread;
std::mutex mMutex;
std::map<int32_t, SensorEnableGuard> mEnabledSensors;
- std::map<int32_t, DataFormat> mEnabledSensorFormats GUARDED_BY(mMutex);
+ std::map<int32_t, SensorExtra> mEnabledSensorsExtra GUARDED_BY(mMutex);
sp<SensorEventQueue> mQueue;
// We must do some of the initialization operations on the worker thread, because the API relies
@@ -248,17 +254,16 @@
}
void handleEvent(const ASensorEvent& event) {
- DataFormat format;
+ PoseEvent value;
{
std::lock_guard lock(mMutex);
- auto iter = mEnabledSensorFormats.find(event.sensor);
- if (iter == mEnabledSensorFormats.end()) {
+ auto iter = mEnabledSensorsExtra.find(event.sensor);
+ if (iter == mEnabledSensorsExtra.end()) {
// This can happen if we have any pending events shortly after stopping.
return;
}
- format = iter->second;
+ value = parseEvent(event, iter->second.format, &iter->second.discontinuityCount);
}
- auto value = parseEvent(event, format);
mListener->onPose(event.timestamp, event.sensor, value.pose, value.twist,
value.isNewReference);
}
@@ -274,6 +279,10 @@
return DataFormat::kQuaternion;
}
+ if (sensor->getType() == ASENSOR_TYPE_HEAD_TRACKER) {
+ return DataFormat::kRotationVectorsAndDiscontinuityCount;
+ }
+
if (sensor->getStringType() == "com.google.hardware.sensor.hid_dynamic.headtracker") {
return DataFormat::kRotationVectorsAndFlags;
}
@@ -313,8 +322,8 @@
return std::nullopt;
}
- static PoseEvent parseEvent(const ASensorEvent& event, DataFormat format) {
- // TODO(ytai): Add more types.
+ static PoseEvent parseEvent(const ASensorEvent& event, DataFormat format,
+ std::optional<int32_t>* discontinutyCount) {
switch (format) {
case DataFormat::kQuaternion: {
Eigen::Quaternionf quat(event.data[3], event.data[0], event.data[1], event.data[2]);
@@ -338,6 +347,21 @@
(flags & (1 << 0)) != 0};
}
+ case DataFormat::kRotationVectorsAndDiscontinuityCount: {
+ Eigen::Vector3f rotation = {event.head_tracker.rx, event.head_tracker.ry,
+ event.head_tracker.rz};
+ Eigen::Vector3f twist = {event.head_tracker.vx, event.head_tracker.vy,
+ event.head_tracker.rz};
+ Eigen::Quaternionf quat = rotationVectorToQuaternion(rotation);
+ bool isNewReference =
+ !discontinutyCount->has_value() ||
+ discontinutyCount->value() != event.head_tracker.discontinuity_count;
+ *discontinutyCount = event.head_tracker.discontinuity_count;
+
+ return PoseEvent{Pose3f(quat), Twist3f(Eigen::Vector3f::Zero(), twist),
+ isNewReference};
+ }
+
default:
LOG_ALWAYS_FATAL("Unexpected sensor type: %d", static_cast<int>(format));
}
diff --git a/media/libheadtracking/StillnessDetector-test.cpp b/media/libheadtracking/StillnessDetector-test.cpp
new file mode 100644
index 0000000..b6cd479
--- /dev/null
+++ b/media/libheadtracking/StillnessDetector-test.cpp
@@ -0,0 +1,167 @@
+/*
+ * 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include "QuaternionUtil.h"
+#include "StillnessDetector.h"
+#include "TestUtil.h"
+
+namespace android {
+namespace media {
+namespace {
+
+using Eigen::Quaternionf;
+using Eigen::Vector3f;
+using Options = StillnessDetector::Options;
+
+class StillnessDetectorTest : public testing::TestWithParam<bool> {
+ public:
+ void SetUp() override { mDefaultValue = GetParam(); }
+
+ protected:
+ bool mDefaultValue;
+};
+
+TEST_P(StillnessDetectorTest, Still) {
+ StillnessDetector detector(Options{.defaultValue = mDefaultValue,
+ .windowDuration = 1000,
+ .translationalThreshold = 1,
+ .rotationalThreshold = 0.05});
+
+ const Pose3f baseline(Vector3f{1, 2, 3}, Quaternionf::UnitRandom());
+ const Pose3f withinThreshold =
+ baseline * Pose3f(Vector3f(0.3, -0.3, 0), rotateX(0.01) * rotateY(-0.01));
+
+ EXPECT_EQ(mDefaultValue, detector.calculate(0));
+ detector.setInput(0, baseline);
+ EXPECT_EQ(mDefaultValue, detector.calculate(0));
+ detector.setInput(300, withinThreshold);
+ EXPECT_EQ(mDefaultValue, detector.calculate(300));
+ detector.setInput(600, baseline);
+ EXPECT_EQ(mDefaultValue, detector.calculate(600));
+ detector.setInput(999, withinThreshold);
+ EXPECT_EQ(mDefaultValue, detector.calculate(999));
+ detector.setInput(1000, baseline);
+ EXPECT_TRUE(detector.calculate(1000));
+}
+
+TEST_P(StillnessDetectorTest, ZeroDuration) {
+ StillnessDetector detector(Options{.defaultValue = mDefaultValue, .windowDuration = 0});
+ EXPECT_TRUE(detector.calculate(0));
+ EXPECT_TRUE(detector.calculate(1000));
+}
+
+TEST_P(StillnessDetectorTest, NotStillTranslation) {
+ StillnessDetector detector(Options{.defaultValue = mDefaultValue,
+ .windowDuration = 1000,
+ .translationalThreshold = 1,
+ .rotationalThreshold = 0.05});
+
+ const Pose3f baseline(Vector3f{1, 2, 3}, Quaternionf::UnitRandom());
+ const Pose3f withinThreshold =
+ baseline * Pose3f(Vector3f(0.3, -0.3, 0), rotateX(0.01) * rotateY(-0.01));
+ const Pose3f outsideThreshold = baseline * Pose3f(Vector3f(1, 1, 0));
+
+ EXPECT_EQ(mDefaultValue, detector.calculate(0));
+ detector.setInput(0, baseline);
+ EXPECT_EQ(mDefaultValue, detector.calculate(0));
+ detector.setInput(300, outsideThreshold);
+ EXPECT_EQ(mDefaultValue, detector.calculate(300));
+ detector.setInput(600, baseline);
+ EXPECT_EQ(mDefaultValue, detector.calculate(600));
+ detector.setInput(1299, withinThreshold);
+ EXPECT_FALSE(detector.calculate(1299));
+ detector.setInput(1300, baseline);
+ EXPECT_TRUE(detector.calculate(1300));
+}
+
+TEST_P(StillnessDetectorTest, NotStillRotation) {
+ StillnessDetector detector(Options{.defaultValue = mDefaultValue,
+ .windowDuration = 1000,
+ .translationalThreshold = 1,
+ .rotationalThreshold = 0.05});
+
+ const Pose3f baseline(Vector3f{1, 2, 3}, Quaternionf::UnitRandom());
+ const Pose3f withinThreshold =
+ baseline * Pose3f(Vector3f(0.3, -0.3, 0), rotateX(0.03) * rotateY(-0.03));
+ const Pose3f outsideThreshold = baseline * Pose3f(rotateZ(0.06));
+
+ EXPECT_EQ(mDefaultValue, detector.calculate(0));
+ detector.setInput(0, baseline);
+ EXPECT_EQ(mDefaultValue, detector.calculate(0));
+ detector.setInput(300, outsideThreshold);
+ EXPECT_EQ(mDefaultValue, detector.calculate(300));
+ detector.setInput(600, baseline);
+ EXPECT_EQ(mDefaultValue, detector.calculate(600));
+ detector.setInput(1299, withinThreshold);
+ EXPECT_FALSE(detector.calculate(1299));
+ detector.setInput(1300, baseline);
+ EXPECT_TRUE(detector.calculate(1300));
+}
+
+TEST_P(StillnessDetectorTest, Suppression) {
+ StillnessDetector detector(Options{.defaultValue = mDefaultValue,
+ .windowDuration = 1000,
+ .translationalThreshold = 1,
+ .rotationalThreshold = 0.05});
+
+ const Pose3f baseline(Vector3f{1, 2, 3}, Quaternionf::UnitRandom());
+ const Pose3f outsideThreshold = baseline * Pose3f(Vector3f(1.1, 0, 0));
+ const Pose3f middlePoint = baseline * Pose3f(Vector3f(0.55, 0, 0));
+
+ detector.setInput(0, baseline);
+ detector.setInput(1000, baseline);
+ EXPECT_TRUE(detector.calculate(1000));
+ detector.setInput(1100, outsideThreshold);
+ EXPECT_FALSE(detector.calculate(1100));
+ detector.setInput(1500, middlePoint);
+ EXPECT_FALSE(detector.calculate(1500));
+ EXPECT_FALSE(detector.calculate(1999));
+ EXPECT_TRUE(detector.calculate(2000));
+}
+
+TEST_P(StillnessDetectorTest, Reset) {
+ StillnessDetector detector(Options{.defaultValue = mDefaultValue,
+ .windowDuration = 1000,
+ .translationalThreshold = 1,
+ .rotationalThreshold = 0.05});
+
+ const Pose3f baseline(Vector3f{1, 2, 3}, Quaternionf::UnitRandom());
+ const Pose3f withinThreshold =
+ baseline * Pose3f(Vector3f(0.3, -0.3, 0), rotateX(0.01) * rotateY(-0.01));
+ EXPECT_EQ(mDefaultValue, detector.calculate(0));
+ detector.setInput(300, baseline);
+ EXPECT_EQ(mDefaultValue, detector.calculate(300));
+ detector.reset();
+ detector.setInput(600, baseline);
+ EXPECT_EQ(mDefaultValue, detector.calculate(600));
+ detector.setInput(900, withinThreshold);
+ EXPECT_EQ(mDefaultValue, detector.calculate(900));
+ detector.setInput(1200, baseline);
+ EXPECT_EQ(mDefaultValue, detector.calculate(1200));
+ detector.setInput(1599, withinThreshold);
+ EXPECT_EQ(mDefaultValue, detector.calculate(1599));
+ detector.setInput(1600, baseline);
+ EXPECT_TRUE(detector.calculate(1600));
+}
+
+INSTANTIATE_TEST_SUITE_P(StillnessDetectorTestParametrized, StillnessDetectorTest,
+ testing::Values(false, true));
+
+} // namespace
+} // namespace media
+} // namespace android
diff --git a/media/libheadtracking/StillnessDetector.cpp b/media/libheadtracking/StillnessDetector.cpp
new file mode 100644
index 0000000..be7c893
--- /dev/null
+++ b/media/libheadtracking/StillnessDetector.cpp
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ */
+
+#include "StillnessDetector.h"
+
+namespace android {
+namespace media {
+
+StillnessDetector::StillnessDetector(const Options& options)
+ : mOptions(options), mCosHalfRotationalThreshold(cos(mOptions.rotationalThreshold / 2)) {}
+
+void StillnessDetector::reset() {
+ mFifo.clear();
+ mWindowFull = false;
+ mSuppressionDeadline.reset();
+}
+
+void StillnessDetector::setInput(int64_t timestamp, const Pose3f& input) {
+ mFifo.push_back(TimestampedPose{timestamp, input});
+ discardOld(timestamp);
+}
+
+bool StillnessDetector::calculate(int64_t timestamp) {
+ discardOld(timestamp);
+
+ // Check whether all the poses in the queue are in the proximity of the new one. We want to do
+ // this before checking the overriding conditions below, in order to update the suppression
+ // deadline correctly. We always go from end to start, to find the most recent pose that
+ // violated stillness and update the suppression deadline if it has not been set or if the new
+ // one ends after the current one.
+ bool moved = false;
+
+ if (!mFifo.empty()) {
+ for (auto iter = mFifo.rbegin() + 1; iter != mFifo.rend(); ++iter) {
+ const auto& event = *iter;
+ if (!areNear(event.pose, mFifo.back().pose)) {
+ // Enable suppression for the duration of the window.
+ int64_t deadline = event.timestamp + mOptions.windowDuration;
+ if (!mSuppressionDeadline.has_value() || mSuppressionDeadline.value() < deadline) {
+ mSuppressionDeadline = deadline;
+ }
+ moved = true;
+ break;
+ }
+ }
+ }
+
+ // If the window has not been full, return the default value.
+ if (!mWindowFull) {
+ return mOptions.defaultValue;
+ }
+
+ // Force "in motion" while the suppression deadline is active.
+ if (mSuppressionDeadline.has_value()) {
+ return false;
+ }
+
+ return !moved;
+}
+
+void StillnessDetector::discardOld(int64_t timestamp) {
+ // Handle the special case of the window duration being zero (always considered full).
+ if (mOptions.windowDuration == 0) {
+ mFifo.clear();
+ mWindowFull = true;
+ }
+
+ // Remove any events from the queue that are older than the window. If there were any such
+ // events we consider the window full.
+ const int64_t windowStart = timestamp - mOptions.windowDuration;
+ while (!mFifo.empty() && mFifo.front().timestamp <= windowStart) {
+ mWindowFull = true;
+ mFifo.pop_front();
+ }
+
+ // Expire the suppression deadline.
+ if (mSuppressionDeadline.has_value() && mSuppressionDeadline <= timestamp) {
+ mSuppressionDeadline.reset();
+ }
+}
+
+bool StillnessDetector::areNear(const Pose3f& pose1, const Pose3f& pose2) const {
+ // Check translation. We use the L1 norm to reduce computational load on expense of accuracy.
+ // The L1 norm is an upper bound for the actual (L2) norm, so this approach will err on the side
+ // of "not near".
+ if ((pose1.translation() - pose2.translation()).lpNorm<1>() > mOptions.translationalThreshold) {
+ return false;
+ }
+
+ // Check orientation.
+ // The angle x between the quaternions is greater than that threshold iff
+ // cos(x/2) < cos(threshold/2).
+ // cos(x/2) can be efficiently calculated as the dot product of both quaternions.
+ if (pose1.rotation().dot(pose2.rotation()) < mCosHalfRotationalThreshold) {
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace media
+} // namespace android
diff --git a/media/libheadtracking/StillnessDetector.h b/media/libheadtracking/StillnessDetector.h
new file mode 100644
index 0000000..ee4b2d8
--- /dev/null
+++ b/media/libheadtracking/StillnessDetector.h
@@ -0,0 +1,106 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <deque>
+
+#include <media/Pose.h>
+
+namespace android {
+namespace media {
+
+/**
+ * Given a stream of poses, determines if the pose is stable ("still").
+ * Stillness is defined as all poses in the recent history ("window") being near the most recent
+ * sample.
+ *
+ * Typical usage:
+ *
+ * StillnessDetector detector(StilnessDetector::Options{...});
+ *
+ * while (...) {
+ * detector.setInput(timestamp, pose);
+ * bool still = detector.calculate(timestamp);
+ * }
+ *
+ * The detection is not considered reliable until a sufficient number of samples has been provided
+ * for an initial fill-up of the window. During that time, the detector will return whatever default
+ * value has been configured.
+ * The reset() method can be used to empty the window again and get back to this initial state.
+ * In the special case of the window size being 0, the state will always be considered "still".
+ */
+class StillnessDetector {
+ public:
+ /**
+ * Configuration options for the detector.
+ */
+ struct Options {
+ /**
+ * During the initial fill of the window, should we consider the state still?
+ */
+ bool defaultValue;
+ /**
+ * How long is the window, in ticks. The special value of 0 indicates that the stream is
+ * always considered still.
+ */
+ int64_t windowDuration;
+ /**
+ * How much of a translational deviation from the target (in meters) is considered motion.
+ * This is an approximate quantity - the actual threshold might be a little different as we
+ * trade-off accuracy with computational efficiency.
+ */
+ float translationalThreshold;
+ /**
+ * How much of a rotational deviation from the target (in radians) is considered motion.
+ * This is an approximate quantity - the actual threshold might be a little different as we
+ * trade-off accuracy with computational efficiency.
+ */
+ float rotationalThreshold;
+ };
+
+ /** Ctor. */
+ explicit StillnessDetector(const Options& options);
+
+ /** Clear the window. */
+ void reset();
+ /** Push a new sample. */
+ void setInput(int64_t timestamp, const Pose3f& input);
+ /** Calculate whether the stream is still at the given timestamp. */
+ bool calculate(int64_t timestamp);
+
+ private:
+ struct TimestampedPose {
+ int64_t timestamp;
+ Pose3f pose;
+ };
+
+ const Options mOptions;
+ // Precalculated cos(mOptions.rotationalThreshold / 2)
+ const float mCosHalfRotationalThreshold;
+ std::deque<TimestampedPose> mFifo;
+ bool mWindowFull = false;
+ // As soon as motion is detected, this will be set for the time of detection + window duration,
+ // and during this time we will always consider outselves in motion without checking. This is
+ // used for hyteresis purposes, since because of the approximate method we use for determining
+ // stillness, we may toggle back and forth at a rate faster than the window side.
+ std::optional<int64_t> mSuppressionDeadline;
+
+ bool areNear(const Pose3f& pose1, const Pose3f& pose2) const;
+ void discardOld(int64_t timestamp);
+};
+
+} // namespace media
+} // namespace android
diff --git a/media/libheadtracking/include/media/HeadTrackingProcessor.h b/media/libheadtracking/include/media/HeadTrackingProcessor.h
index 9fea273..2af560e 100644
--- a/media/libheadtracking/include/media/HeadTrackingProcessor.h
+++ b/media/libheadtracking/include/media/HeadTrackingProcessor.h
@@ -42,6 +42,12 @@
float rotationalDriftTimeConstant = std::numeric_limits<float>::infinity();
int64_t freshnessTimeout = std::numeric_limits<int64_t>::max();
float predictionDuration = 0;
+ int64_t autoRecenterWindowDuration = std::numeric_limits<int64_t>::max();
+ float autoRecenterTranslationalThreshold = std::numeric_limits<float>::infinity();
+ float autoRecenterRotationalThreshold = std::numeric_limits<float>::infinity();
+ int64_t screenStillnessWindowDuration = 0;
+ float screenStillnessTranslationalThreshold = std::numeric_limits<float>::infinity();
+ float screenStillnessRotationalThreshold = std::numeric_limits<float>::infinity();
};
/** Sets the desired head-tracking mode. */
diff --git a/media/libheif/Android.bp b/media/libheif/Android.bp
index 6a3427e..55ba61a 100644
--- a/media/libheif/Android.bp
+++ b/media/libheif/Android.bp
@@ -26,7 +26,5 @@
"-Wall",
],
- include_dirs: [],
-
export_include_dirs: ["include"],
}
diff --git a/media/libmediahelper/Android.bp b/media/libmediahelper/Android.bp
index 9b54199..a433fc6 100644
--- a/media/libmediahelper/Android.bp
+++ b/media/libmediahelper/Android.bp
@@ -20,7 +20,7 @@
},
apex_available: [
"//apex_available:platform",
- "com.android.bluetooth.updatable",
+ "com.android.bluetooth",
"com.android.media",
"com.android.media.swcodec",
],
diff --git a/media/libmediametrics/MediaMetricsItem.cpp b/media/libmediametrics/MediaMetricsItem.cpp
index a7ec975..57fc49d 100644
--- a/media/libmediametrics/MediaMetricsItem.cpp
+++ b/media/libmediametrics/MediaMetricsItem.cpp
@@ -57,18 +57,19 @@
// This may be found in frameworks/av/media/libmediametrics/include/MediaMetricsConstants.h
static std::unordered_map<std::string, int32_t> map{
{"", NO_ERROR},
- {AMEDIAMETRICS_PROP_ERROR_VALUE_ARGUMENT, BAD_VALUE},
- {AMEDIAMETRICS_PROP_ERROR_VALUE_IO, DEAD_OBJECT},
- {AMEDIAMETRICS_PROP_ERROR_VALUE_MEMORY, NO_MEMORY},
- {AMEDIAMETRICS_PROP_ERROR_VALUE_SECURITY, PERMISSION_DENIED},
- {AMEDIAMETRICS_PROP_ERROR_VALUE_STATE, INVALID_OPERATION},
- {AMEDIAMETRICS_PROP_ERROR_VALUE_TIMEOUT, WOULD_BLOCK},
- {AMEDIAMETRICS_PROP_ERROR_VALUE_UNKNOWN, UNKNOWN_ERROR},
+ {AMEDIAMETRICS_PROP_STATUS_VALUE_OK, NO_ERROR},
+ {AMEDIAMETRICS_PROP_STATUS_VALUE_ARGUMENT, BAD_VALUE},
+ {AMEDIAMETRICS_PROP_STATUS_VALUE_IO, DEAD_OBJECT},
+ {AMEDIAMETRICS_PROP_STATUS_VALUE_MEMORY, NO_MEMORY},
+ {AMEDIAMETRICS_PROP_STATUS_VALUE_SECURITY, PERMISSION_DENIED},
+ {AMEDIAMETRICS_PROP_STATUS_VALUE_STATE, INVALID_OPERATION},
+ {AMEDIAMETRICS_PROP_STATUS_VALUE_TIMEOUT, WOULD_BLOCK},
+ {AMEDIAMETRICS_PROP_STATUS_VALUE_UNKNOWN, UNKNOWN_ERROR},
};
return map;
}
-status_t errorStringToStatus(const char *error) {
+status_t statusStringToStatus(const char *error) {
const auto& map = getErrorStringMap();
if (error == nullptr || error[0] == '\0') return NO_ERROR;
auto it = map.find(error);
diff --git a/media/libmediametrics/include/MediaMetricsConstants.h b/media/libmediametrics/include/MediaMetricsConstants.h
index 5d0eca0..4247375 100644
--- a/media/libmediametrics/include/MediaMetricsConstants.h
+++ b/media/libmediametrics/include/MediaMetricsConstants.h
@@ -25,6 +25,9 @@
* 2) Consistent behavior and documentation.
*/
+#define AMEDIAMETRICS_INITIAL_MAX_VOLUME (0.f)
+#define AMEDIAMETRICS_INITIAL_MIN_VOLUME (1.f)
+
/*
* Taxonomy of audio keys
*
@@ -61,6 +64,10 @@
#define AMEDIAMETRICS_KEY_AUDIO_FLINGER AMEDIAMETRICS_KEY_PREFIX_AUDIO "flinger"
#define AMEDIAMETRICS_KEY_AUDIO_POLICY AMEDIAMETRICS_KEY_PREFIX_AUDIO "policy"
+// Error keys
+#define AMEDIAMETRICS_KEY_AUDIO_TRACK_ERROR AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "error"
+#define AMEDIAMETRICS_KEY_AUDIO_RECORD_ERROR AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "error"
+
/*
* MediaMetrics Properties are unified space for consistency and readability.
*/
@@ -112,22 +119,15 @@
#define AMEDIAMETRICS_PROP_DEVICETIMENS "deviceTimeNs" // int64_t playback/record time
#define AMEDIAMETRICS_PROP_DEVICEVOLUME "deviceVolume" // double - average device volume
+#define AMEDIAMETRICS_PROP_DEVICEMAXVOLUMEDURATIONNS "deviceMaxVolumeDurationNs" // int64_t
+#define AMEDIAMETRICS_PROP_DEVICEMAXVOLUME "deviceMaxVolume" // double - maximum device volume
+#define AMEDIAMETRICS_PROP_DEVICEMINVOLUMEDURATIONNS "deviceMinVolumeDurationNs" // int64_t
+#define AMEDIAMETRICS_PROP_DEVICEMINVOLUME "deviceMinVolume" // double - minimum device volume
+
#define AMEDIAMETRICS_PROP_DIRECTION "direction" // string AAudio input or output
#define AMEDIAMETRICS_PROP_DURATIONNS "durationNs" // int64 duration time span
#define AMEDIAMETRICS_PROP_ENCODING "encoding" // string value of format
-// Error statistics
-#define AMEDIAMETRICS_PROP_ERROR "error#" // string, empty or one of
- // AMEDIAMETRICS_PROP_ERROR_VALUE_*
- // Used for error categorization.
-#define AMEDIAMETRICS_PROP_ERRORSUBCODE "errorSubCode#" // int32, specific code for error
- // used in conjunction with error#.
-#define AMEDIAMETRICS_PROP_ERRORMESSAGE "errorMessage#" // string, supplemental to error.
- // Arbitrary information treated as
- // informational, may be logcat msg,
- // or an exception with stack trace.
- // Treated as "debug" information.
-
#define AMEDIAMETRICS_PROP_EVENT "event#" // string value (often func name)
#define AMEDIAMETRICS_PROP_EXECUTIONTIMENS "executionTimeNs" // time to execute the event
@@ -159,7 +159,17 @@
#define AMEDIAMETRICS_PROP_STARTUPMS "startupMs" // double value
// State is "ACTIVE" or "STOPPED" for AudioRecord
#define AMEDIAMETRICS_PROP_STATE "state" // string
-#define AMEDIAMETRICS_PROP_STATUS "status" // int32 status_t
+#define AMEDIAMETRICS_PROP_STATUS "status#" // int32 status_t
+ // AAudio uses their own status codes
+// Supplemental information to the status code.
+#define AMEDIAMETRICS_PROP_STATUSSUBCODE "statusSubCode" // int32, specific code
+ // used in conjunction with status.
+#define AMEDIAMETRICS_PROP_STATUSMESSAGE "statusMessage" // string, supplemental info.
+ // Arbitrary information treated as
+ // informational, may be logcat msg,
+ // or an exception with stack trace.
+ // Treated as "debug" information.
+
#define AMEDIAMETRICS_PROP_STREAMTYPE "streamType" // string (AudioTrack)
#define AMEDIAMETRICS_PROP_THREADID "threadId" // int32 value io handle
#define AMEDIAMETRICS_PROP_THROTTLEMS "throttleMs" // double
@@ -234,16 +244,20 @@
// https://cs.android.com/android/platform/superproject/+/master:frameworks/native/libs/binder/include/binder/Status.h;drc=88e25c0861499ee3ab885814dddc097ab234cb7b;l=57
// https://cs.android.com/android/platform/superproject/+/master:frameworks/base/media/java/android/media/AudioSystem.java;drc=3ac246c43294d7f7012bdcb0ccb7bae1aa695bd4;l=785
// https://cs.android.com/android/platform/superproject/+/master:frameworks/av/media/libaaudio/include/aaudio/AAudio.h;drc=cfd3a6fa3aaaf712a890dc02452b38ef401083b8;l=120
+// https://abseil.io/docs/cpp/guides/status-codes
-// Error category:
-// An empty error string indicates no error.
+// Status errors:
+// An empty status string or "ok" is interpreted as no error.
+#define AMEDIAMETRICS_PROP_STATUS_VALUE_OK "ok"
// Error category: argument
// IllegalArgumentException
// NullPointerException
// BAD_VALUE
+// absl::INVALID_ARGUMENT
+// absl::OUT_OF_RANGE
// Out of range, out of bounds.
-#define AMEDIAMETRICS_PROP_ERROR_VALUE_ARGUMENT "argument"
+#define AMEDIAMETRICS_PROP_STATUS_VALUE_ARGUMENT "argument"
// Error category: io
// IOException
@@ -254,36 +268,48 @@
// file or ioctl failure
// Service, rpc, binder, or socket failure.
// Hardware or device failure.
-#define AMEDIAMETRICS_PROP_ERROR_VALUE_IO "io"
+#define AMEDIAMETRICS_PROP_STATUS_VALUE_IO "io"
// Error category: outOfMemory
// OutOfMemoryException
// NO_MEMORY
-#define AMEDIAMETRICS_PROP_ERROR_VALUE_MEMORY "memory"
+// absl::RESOURCE_EXHAUSTED
+#define AMEDIAMETRICS_PROP_STATUS_VALUE_MEMORY "memory"
// Error category: security
// SecurityException
// PERMISSION_DENIED
-#define AMEDIAMETRICS_PROP_ERROR_VALUE_SECURITY "security"
+// absl::PERMISSION_DENIED
+// absl::UNAUTHENTICATED
+#define AMEDIAMETRICS_PROP_STATUS_VALUE_SECURITY "security"
// Error category: state
// IllegalStateException
// UnsupportedOperationException
// INVALID_OPERATION
// NO_INIT
+// absl::NOT_FOUND
+// absl::ALREADY_EXISTS
+// absl::FAILED_PRECONDITION
+// absl::UNAVAILABLE
+// absl::UNIMPLEMENTED
// Functionality not implemented (argument may or may not be correct).
// Call unexpected or out of order.
-#define AMEDIAMETRICS_PROP_ERROR_VALUE_STATE "state"
+#define AMEDIAMETRICS_PROP_STATUS_VALUE_STATE "state"
// Error category: timeout
// TimeoutException
// WOULD_BLOCK
-#define AMEDIAMETRICS_PROP_ERROR_VALUE_TIMEOUT "timeout"
+// absl::DEADLINE_EXCEEDED
+// absl::ABORTED
+#define AMEDIAMETRICS_PROP_STATUS_VALUE_TIMEOUT "timeout"
// Error category: unknown
// Exception (Java specified not listed above, or custom app/service)
// UNKNOWN_ERROR
+// absl::INTERNAL
+// absl::DATA_LOSS
// Catch-all bucket for errors not listed above.
-#define AMEDIAMETRICS_PROP_ERROR_VALUE_UNKNOWN "unknown"
+#define AMEDIAMETRICS_PROP_STATUS_VALUE_UNKNOWN "unknown"
#endif // ANDROID_MEDIA_MEDIAMETRICSCONSTANTS_H
diff --git a/media/libmediametrics/include/media/MediaMetricsItem.h b/media/libmediametrics/include/media/MediaMetricsItem.h
index 87f608f..de56665 100644
--- a/media/libmediametrics/include/media/MediaMetricsItem.h
+++ b/media/libmediametrics/include/media/MediaMetricsItem.h
@@ -106,34 +106,34 @@
};
/*
- * Helper for error conversions
+ * Helper for status conversions
*/
-static inline constexpr const char* statusToErrorString(status_t status) {
+inline constexpr const char* statusToStatusString(status_t status) {
switch (status) {
- case NO_ERROR:
- return "";
case BAD_VALUE:
- return AMEDIAMETRICS_PROP_ERROR_VALUE_ARGUMENT;
+ return AMEDIAMETRICS_PROP_STATUS_VALUE_ARGUMENT;
case DEAD_OBJECT:
case FAILED_TRANSACTION:
- return AMEDIAMETRICS_PROP_ERROR_VALUE_IO;
+ return AMEDIAMETRICS_PROP_STATUS_VALUE_IO;
case NO_MEMORY:
- return AMEDIAMETRICS_PROP_ERROR_VALUE_MEMORY;
+ return AMEDIAMETRICS_PROP_STATUS_VALUE_MEMORY;
case PERMISSION_DENIED:
- return AMEDIAMETRICS_PROP_ERROR_VALUE_SECURITY;
+ return AMEDIAMETRICS_PROP_STATUS_VALUE_SECURITY;
case NO_INIT:
case INVALID_OPERATION:
- return AMEDIAMETRICS_PROP_ERROR_VALUE_STATE;
+ return AMEDIAMETRICS_PROP_STATUS_VALUE_STATE;
case WOULD_BLOCK:
- return AMEDIAMETRICS_PROP_ERROR_VALUE_TIMEOUT;
- case UNKNOWN_ERROR:
+ return AMEDIAMETRICS_PROP_STATUS_VALUE_TIMEOUT;
default:
- return AMEDIAMETRICS_PROP_ERROR_VALUE_UNKNOWN;
+ if (status >= 0) return AMEDIAMETRICS_PROP_STATUS_VALUE_OK; // non-negative values "OK"
+ [[fallthrough]]; // negative values are error.
+ case UNKNOWN_ERROR:
+ return AMEDIAMETRICS_PROP_STATUS_VALUE_UNKNOWN;
}
}
-status_t errorStringToStatus(const char *error);
+status_t statusStringToStatus(const char *error);
/*
* Time printing
diff --git a/media/libmediaplayerservice/Android.bp b/media/libmediaplayerservice/Android.bp
index e70e3b3..a23d1d9 100644
--- a/media/libmediaplayerservice/Android.bp
+++ b/media/libmediaplayerservice/Android.bp
@@ -71,6 +71,7 @@
header_libs: [
"media_plugin_headers",
"libmediautils_headers",
+ "libstagefright_rtsp_headers",
],
static_libs: [
@@ -78,6 +79,9 @@
"libstagefright_nuplayer",
"libstagefright_rtsp",
"libstagefright_timedtext",
+ // this needs it, but it can get it transitively through libstagefright.
+ // i'm going to leave it here.
+ "libstagefright_webm",
"framework-permission-aidl-cpp",
],
@@ -90,13 +94,12 @@
"libmediautils_headers",
],
- include_dirs: [
- "frameworks/av/media/libstagefright/rtsp",
- "frameworks/av/media/libstagefright/webm",
- ],
-
local_include_dirs: ["include"],
+ export_include_dirs: [
+ ".",
+ ],
+
cflags: [
"-Werror",
"-Wno-error=deprecated-declarations",
diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp
index 05f7365..cd411ea 100644
--- a/media/libmediaplayerservice/MediaPlayerFactory.cpp
+++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp
@@ -30,7 +30,7 @@
#include "MediaPlayerFactory.h"
#include "TestPlayerStub.h"
-#include "nuplayer/NuPlayerDriver.h"
+#include <nuplayer/NuPlayerDriver.h>
namespace android {
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index c7a7a3a..3b5e1e2 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -82,7 +82,7 @@
#include "MediaPlayerFactory.h"
#include "TestPlayerStub.h"
-#include "nuplayer/NuPlayerDriver.h"
+#include <nuplayer/NuPlayerDriver.h>
static const int kDumpLockRetries = 50;
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index bffd7b3..ea1fdf4 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -16,13 +16,16 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "StagefrightRecorder"
+#define ATRACE_TAG ATRACE_TAG_VIDEO
+#include <utils/Trace.h>
#include <inttypes.h>
// TODO/workaround: including base logging now as it conflicts with ADebug.h
// and it must be included first.
#include <android-base/logging.h>
#include <utils/Log.h>
-#include "WebmWriter.h"
+#include <webm/WebmWriter.h>
+
#include "StagefrightRecorder.h"
#include <algorithm>
@@ -64,7 +67,7 @@
#include <system/audio.h>
-#include "ARTPWriter.h"
+#include <media/stagefright/rtsp/ARTPWriter.h>
namespace android {
@@ -1856,6 +1859,7 @@
// Set up the appropriate MediaSource depending on the chosen option
status_t StagefrightRecorder::setupMediaSource(
sp<MediaSource> *mediaSource) {
+ ATRACE_CALL();
if (mVideoSource == VIDEO_SOURCE_DEFAULT
|| mVideoSource == VIDEO_SOURCE_CAMERA) {
sp<CameraSource> cameraSource;
@@ -1936,6 +1940,7 @@
status_t StagefrightRecorder::setupVideoEncoder(
const sp<MediaSource> &cameraSource,
sp<MediaCodecSource> *source) {
+ ATRACE_CALL();
source->clear();
sp<AMessage> format = new AMessage();
@@ -2114,6 +2119,7 @@
}
status_t StagefrightRecorder::setupAudioEncoder(const sp<MediaWriter>& writer) {
+ ATRACE_CALL();
status_t status = BAD_VALUE;
if (OK != (status = checkAudioEncoderCapabilities())) {
return status;
diff --git a/media/libmediaplayerservice/fuzzer/Android.bp b/media/libmediaplayerservice/fuzzer/Android.bp
index d83d3c9..a36f1d6 100644
--- a/media/libmediaplayerservice/fuzzer/Android.bp
+++ b/media/libmediaplayerservice/fuzzer/Android.bp
@@ -28,9 +28,6 @@
cc_defaults {
name: "libmediaplayerserviceFuzzer_defaults",
- include_dirs: [
- "frameworks/av/media/libmediaplayerservice",
- ],
static_libs: [
"libmediaplayerservice",
"liblog",
diff --git a/media/libmediaplayerservice/nuplayer/Android.bp b/media/libmediaplayerservice/nuplayer/Android.bp
index 6d338db..71b8c2b 100644
--- a/media/libmediaplayerservice/nuplayer/Android.bp
+++ b/media/libmediaplayerservice/nuplayer/Android.bp
@@ -37,20 +37,22 @@
"StreamingSource.cpp",
],
+ local_include_dirs: [
+ "include/nuplayer",
+ ],
+
+ export_include_dirs: [
+ "include",
+ ],
+
header_libs: [
"libmediadrm_headers",
"libmediametrics_headers",
"media_plugin_headers",
- ],
-
- include_dirs: [
- "frameworks/av/media/libstagefright",
- "frameworks/av/media/libstagefright/httplive",
- "frameworks/av/media/libstagefright/include",
- "frameworks/av/media/libstagefright/mpeg2ts",
- "frameworks/av/media/libstagefright/rtsp",
- "frameworks/av/media/libstagefright/timedtext",
- "frameworks/native/include/android",
+ "libstagefright_headers",
+ "libstagefright_httplive_headers",
+ "libstagefright_mpeg2support_headers",
+ "libstagefright_rtsp_headers",
],
cflags: [
@@ -78,6 +80,7 @@
static_libs: [
"libplayerservice_datasource",
+ "libstagefright_timedtext",
],
name: "libstagefright_nuplayer",
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 439dbe8..36e4d4a 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -20,7 +20,6 @@
#include "GenericSource.h"
#include "NuPlayerDrm.h"
-#include "AnotherPacketSource.h"
#include <binder/IServiceManager.h>
#include <cutils/properties.h>
#include <datasource/PlayerServiceDataSourceFactory.h>
@@ -44,6 +43,7 @@
#include <media/stagefright/MediaExtractorFactory.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
+#include <mpeg2ts/AnotherPacketSource.h>
namespace android {
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
index 77e7885..4e71e89 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
@@ -19,8 +19,6 @@
#include <utils/Log.h>
#include "HTTPLiveSource.h"
-
-#include "AnotherPacketSource.h"
#include "LiveDataSource.h"
#include <media/IMediaHTTPService.h>
@@ -31,6 +29,7 @@
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/Utils.h>
+#include <mpeg2ts/AnotherPacketSource.h>
// default buffer prepare/ready/underflow marks
static const int kReadyMarkMs = 5000; // 5 seconds
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 9ae7ddb..c6b22a6 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -35,9 +35,7 @@
#include "RTSPSource.h"
#include "StreamingSource.h"
#include "GenericSource.h"
-#include "TextDescriptions.h"
-
-#include "ATSParser.h"
+#include <timedtext/TextDescriptions.h>
#include <cutils/properties.h>
@@ -56,6 +54,8 @@
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
+#include <mpeg2ts/ATSParser.h>
+
#include <gui/IGraphicBufferProducer.h>
#include <gui/Surface.h>
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 2c1f158..52b2041 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -40,10 +40,9 @@
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/SurfaceUtils.h>
+#include <mpeg2ts/ATSParser.h>
#include <gui/Surface.h>
-#include "ATSParser.h"
-
namespace android {
static float kDisplayRefreshingRate = 60.f; // TODO: get this from the display
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
index 793014e..cb91fd9 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
@@ -30,8 +30,7 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/MediaErrors.h>
-
-#include "ATSParser.h"
+#include <mpeg2ts/ATSParser.h>
namespace android {
diff --git a/media/libmediaplayerservice/nuplayer/RTPSource.cpp b/media/libmediaplayerservice/nuplayer/RTPSource.cpp
index 4d6a483..6a17972 100644
--- a/media/libmediaplayerservice/nuplayer/RTPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTPSource.cpp
@@ -336,7 +336,7 @@
*durationUs = 0ll;
int64_t audioDurationUs;
- if (mAudioTrack != NULL
+ if (mAudioTrack != NULL && mAudioTrack->getFormat() != NULL
&& mAudioTrack->getFormat()->findInt64(
kKeyDuration, &audioDurationUs)
&& audioDurationUs > *durationUs) {
@@ -344,7 +344,7 @@
}
int64_t videoDurationUs;
- if (mVideoTrack != NULL
+ if (mVideoTrack != NULL && mVideoTrack->getFormat() != NULL
&& mVideoTrack->getFormat()->findInt64(
kKeyDuration, &videoDurationUs)
&& videoDurationUs > *durationUs) {
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index 8e05de8..75cedcc 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -20,13 +20,12 @@
#include "RTSPSource.h"
-#include "AnotherPacketSource.h"
-#include "MyHandler.h"
-#include "SDPLoader.h"
-
#include <media/IMediaHTTPService.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
+#include <media/stagefright/rtsp/MyHandler.h>
+#include <media/stagefright/rtsp/SDPLoader.h>
+#include <mpeg2ts/AnotherPacketSource.h>
namespace android {
diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
index bec27d3..9d67ca4 100644
--- a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
@@ -20,8 +20,6 @@
#include "StreamingSource.h"
-#include "ATSParser.h"
-#include "AnotherPacketSource.h"
#include "NuPlayerStreamListener.h"
#include <media/stagefright/MediaSource.h>
@@ -31,6 +29,8 @@
#include <media/stagefright/foundation/MediaKeys.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
+#include <mpeg2ts/AnotherPacketSource.h>
+#include <mpeg2ts/ATSParser.h>
namespace android {
diff --git a/media/libmediaplayerservice/nuplayer/AWakeLock.h b/media/libmediaplayerservice/nuplayer/include/nuplayer/AWakeLock.h
similarity index 100%
rename from media/libmediaplayerservice/nuplayer/AWakeLock.h
rename to media/libmediaplayerservice/nuplayer/include/nuplayer/AWakeLock.h
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/include/nuplayer/GenericSource.h
similarity index 99%
rename from media/libmediaplayerservice/nuplayer/GenericSource.h
rename to media/libmediaplayerservice/nuplayer/include/nuplayer/GenericSource.h
index 7a2ab8f..80e06f1 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/include/nuplayer/GenericSource.h
@@ -21,11 +21,10 @@
#include "NuPlayer.h"
#include "NuPlayerSource.h"
-#include "ATSParser.h"
-
#include <android-base/unique_fd.h>
#include <media/mediaplayer.h>
#include <media/stagefright/MediaBuffer.h>
+#include <mpeg2ts/ATSParser.h>
namespace android {
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h b/media/libmediaplayerservice/nuplayer/include/nuplayer/HTTPLiveSource.h
similarity index 100%
rename from media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
rename to media/libmediaplayerservice/nuplayer/include/nuplayer/HTTPLiveSource.h
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayer.h
similarity index 100%
rename from media/libmediaplayerservice/nuplayer/NuPlayer.h
rename to media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayer.h
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.h b/media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerCCDecoder.h
similarity index 100%
rename from media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.h
rename to media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerCCDecoder.h
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerDecoder.h
similarity index 100%
rename from media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
rename to media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerDecoder.h
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h b/media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerDecoderBase.h
similarity index 100%
rename from media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
rename to media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerDecoderBase.h
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h b/media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerDecoderPassThrough.h
similarity index 100%
rename from media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h
rename to media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerDecoderPassThrough.h
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerDriver.h
similarity index 100%
rename from media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
rename to media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerDriver.h
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDrm.h b/media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerDrm.h
similarity index 100%
rename from media/libmediaplayerservice/nuplayer/NuPlayerDrm.h
rename to media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerDrm.h
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerRenderer.h
similarity index 100%
rename from media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
rename to media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerRenderer.h
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerSource.h
similarity index 100%
rename from media/libmediaplayerservice/nuplayer/NuPlayerSource.h
rename to media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerSource.h
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.h b/media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerStreamListener.h
similarity index 100%
rename from media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.h
rename to media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerStreamListener.h
diff --git a/media/libmediaplayerservice/nuplayer/RTPSource.h b/media/libmediaplayerservice/nuplayer/include/nuplayer/RTPSource.h
similarity index 95%
rename from media/libmediaplayerservice/nuplayer/RTPSource.h
rename to media/libmediaplayerservice/nuplayer/include/nuplayer/RTPSource.h
index 3b4f9e9..7d9bb8f 100644
--- a/media/libmediaplayerservice/nuplayer/RTPSource.h
+++ b/media/libmediaplayerservice/nuplayer/include/nuplayer/RTPSource.h
@@ -23,25 +23,20 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/rtsp/APacketSource.h>
+#include <media/stagefright/rtsp/ARTPConnection.h>
+#include <media/stagefright/rtsp/ARTPSource.h>
+#include <media/stagefright/rtsp/ASessionDescription.h>
#include <media/stagefright/Utils.h>
#include <media/BufferingSettings.h>
+#include <mpeg2ts/AnotherPacketSource.h>
#include <utils/KeyedVector.h>
#include <utils/Vector.h>
#include <utils/RefBase.h>
-#include "AnotherPacketSource.h"
-#include "APacketSource.h"
-#include "ARTPConnection.h"
-#include "ARTPSource.h"
-#include "ASessionDescription.h"
#include "NuPlayerSource.h"
-
-
-
-
-
namespace android {
struct ALooper;
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.h b/media/libmediaplayerservice/nuplayer/include/nuplayer/RTSPSource.h
similarity index 99%
rename from media/libmediaplayerservice/nuplayer/RTSPSource.h
rename to media/libmediaplayerservice/nuplayer/include/nuplayer/RTSPSource.h
index 03fce08..7497e41 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.h
+++ b/media/libmediaplayerservice/nuplayer/include/nuplayer/RTSPSource.h
@@ -20,7 +20,7 @@
#include "NuPlayerSource.h"
-#include "ATSParser.h"
+#include <mpeg2ts/ATSParser.h>
namespace android {
diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.h b/media/libmediaplayerservice/nuplayer/include/nuplayer/StreamingSource.h
similarity index 100%
rename from media/libmediaplayerservice/nuplayer/StreamingSource.h
rename to media/libmediaplayerservice/nuplayer/include/nuplayer/StreamingSource.h
diff --git a/media/libmediaplayerservice/tests/stagefrightRecorder/Android.bp b/media/libmediaplayerservice/tests/stagefrightRecorder/Android.bp
index 92236ea..6eb8c6f 100644
--- a/media/libmediaplayerservice/tests/stagefrightRecorder/Android.bp
+++ b/media/libmediaplayerservice/tests/stagefrightRecorder/Android.bp
@@ -33,10 +33,6 @@
"StagefrightRecorderTest.cpp",
],
- include_dirs: [
- "frameworks/av/media/libmediaplayerservice",
- ],
-
static_libs: [
"libmediaplayerservice",
"libstagefright_httplive",
diff --git a/media/libmediatranscoding/include/media/ControllerClientInterface.h b/media/libmediatranscoding/include/media/ControllerClientInterface.h
index 9311e2e..ea63da8 100644
--- a/media/libmediatranscoding/include/media/ControllerClientInterface.h
+++ b/media/libmediatranscoding/include/media/ControllerClientInterface.h
@@ -66,7 +66,7 @@
* Returns false if the session doesn't exist, or the client is already requesting the
* session. Returns true otherwise.
*/
- virtual bool addClientUid(ClientIdType clientId, SessionIdType sessionId, uid_t clientUid);
+ virtual bool addClientUid(ClientIdType clientId, SessionIdType sessionId, uid_t clientUid) = 0;
/**
* Retrieves the (unsorted) list of all clients requesting the session identified by
@@ -81,7 +81,7 @@
* Returns false if the session doesn't exist. Returns true otherwise.
*/
virtual bool getClientUids(ClientIdType clientId, SessionIdType sessionId,
- std::vector<int32_t>* out_clientUids);
+ std::vector<int32_t>* out_clientUids) = 0;
protected:
virtual ~ControllerClientInterface() = default;
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 7c7fcac..3784dde 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -470,6 +470,7 @@
void writeHdlrBox();
void writeTkhdBox(uint32_t now);
void writeColrBox();
+ void writeMdcvAndClliBoxes();
void writeMp4aEsdsBox();
void writeMp4vEsdsBox();
void writeAudioFourCCBox();
@@ -4341,6 +4342,7 @@
writePaspBox();
writeColrBox();
+ writeMdcvAndClliBoxes();
mOwner->endBox(); // mp4v, s263 or avc1
}
@@ -4375,6 +4377,54 @@
}
}
+void MPEG4Writer::Track::writeMdcvAndClliBoxes() {
+ sp<MetaData> meta = mSource->getFormat();
+ uint32_t type;
+ const uint8_t* data;
+ size_t size;
+ bool found =
+ meta->findData(kKeyHdrStaticInfo, &type, reinterpret_cast<const void**>(&data), &size);
+ if (found && size == 25) {
+ uint16_t displayPrimariesRX = U16LE_AT(&data[1]);
+ uint16_t displayPrimariesRY = U16LE_AT(&data[3]);
+
+ uint16_t displayPrimariesGX = U16LE_AT(&data[5]);
+ uint16_t displayPrimariesGY = U16LE_AT(&data[7]);
+
+ uint16_t displayPrimariesBX = U16LE_AT(&data[9]);
+ uint16_t displayPrimariesBY = U16LE_AT(&data[11]);
+
+ uint16_t whitePointX = U16LE_AT(&data[13]);
+ uint16_t whitePointY = U16LE_AT(&data[15]);
+
+ uint16_t maxDisplayMasteringLuminance = U16LE_AT(&data[17]);
+ uint16_t minDisplayMasteringLuminance = U16LE_AT(&data[19]);
+
+ uint16_t maxContentLightLevel = U16LE_AT(&data[21]);
+ uint16_t maxPicAverageLightLevel = U16LE_AT(&data[23]);
+
+ mOwner->beginBox("mdcv");
+ mOwner->writeInt16(displayPrimariesGX);
+ mOwner->writeInt16(displayPrimariesGY);
+ mOwner->writeInt16(displayPrimariesBX);
+ mOwner->writeInt16(displayPrimariesBY);
+ mOwner->writeInt16(displayPrimariesRX);
+ mOwner->writeInt16(displayPrimariesRY);
+ mOwner->writeInt16(whitePointX);
+ mOwner->writeInt16(whitePointY);
+ mOwner->writeInt32(maxDisplayMasteringLuminance * 10000);
+ mOwner->writeInt32(minDisplayMasteringLuminance * 10000);
+ mOwner->endBox(); // mdcv.
+
+ mOwner->beginBox("clli");
+ mOwner->writeInt16(maxContentLightLevel);
+ mOwner->writeInt16(maxPicAverageLightLevel);
+ mOwner->endBox(); // clli.
+ } else {
+ ALOGW("Ignoring HDR static info with unexpected size %d", (int)size);
+ }
+}
+
void MPEG4Writer::Track::writeAudioFourCCBox() {
const char *mime;
bool success = mMeta->findCString(kKeyMIMEType, &mime);
diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
index 2ffe728..a3040f4 100644
--- a/media/libstagefright/MediaCodecList.cpp
+++ b/media/libstagefright/MediaCodecList.cpp
@@ -18,8 +18,6 @@
#define LOG_TAG "MediaCodecList"
#include <utils/Log.h>
-#include "MediaCodecListOverrides.h"
-
#include <binder/IServiceManager.h>
#include <media/IMediaCodecList.h>
@@ -34,6 +32,7 @@
#include <media/stagefright/CCodec.h>
#include <media/stagefright/Codec2InfoBuilder.h>
#include <media/stagefright/MediaCodecList.h>
+#include <media/stagefright/MediaCodecListOverrides.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/OmxInfoBuilder.h>
#include <media/stagefright/PersistentSurface.h>
diff --git a/media/libstagefright/MediaCodecListOverrides.cpp b/media/libstagefright/MediaCodecListOverrides.cpp
index 4a167d1..9304e45 100644
--- a/media/libstagefright/MediaCodecListOverrides.cpp
+++ b/media/libstagefright/MediaCodecListOverrides.cpp
@@ -18,8 +18,6 @@
#define LOG_TAG "MediaCodecListOverrides"
#include <utils/Log.h>
-#include "MediaCodecListOverrides.h"
-
#include <cutils/properties.h>
#include <gui/Surface.h>
#include <mediadrm/ICrypto.h>
@@ -30,6 +28,7 @@
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/MediaCodec.h>
#include <media/stagefright/MediaCodecList.h>
+#include <media/stagefright/MediaCodecListOverrides.h>
namespace android {
diff --git a/media/libstagefright/TEST_MAPPING b/media/libstagefright/TEST_MAPPING
index 0987a5b..91a44d1 100644
--- a/media/libstagefright/TEST_MAPPING
+++ b/media/libstagefright/TEST_MAPPING
@@ -40,6 +40,50 @@
"exclude-filter": "android.media.audio.cts.AudioRecordTest"
}
]
+ },
+ {
+ "name": "CtsMediaDecoderTestCases",
+ "options": [
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.RequiresDevice"
+ }
+ ]
+ },
+ {
+ "name": "CtsMediaEncoderTestCases",
+ "options": [
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.RequiresDevice"
+ }
+ ]
+ },
+ {
+ "name": "CtsMediaCodecTestCases",
+ "options": [
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.RequiresDevice"
+ }
+ ]
+ },
+ {
+ "name": "CtsMediaPlayerTestCases",
+ "options": [
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.RequiresDevice"
+ }
+ ]
}
],
"presubmit": [
diff --git a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
index fb6c4e2..bb1cb0b 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
+++ b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
@@ -354,7 +354,7 @@
}
if (mpeg4type->eProfile != OMX_VIDEO_MPEG4ProfileCore ||
- mpeg4type->eLevel != OMX_VIDEO_MPEG4Level2 ||
+ mpeg4type->eLevel > OMX_VIDEO_MPEG4Level2 ||
(mpeg4type->nAllowedPictureTypes & OMX_VIDEO_PictureTypeB) ||
mpeg4type->nBFrames != 0 ||
mpeg4type->nIDCVLCThreshold != 0 ||
diff --git a/media/libstagefright/filters/Android.bp b/media/libstagefright/filters/Android.bp
index b46a271..e6d59ad 100644
--- a/media/libstagefright/filters/Android.bp
+++ b/media/libstagefright/filters/Android.bp
@@ -22,6 +22,14 @@
"ZeroFilter.cpp",
],
+ export_include_dirs: [
+ "include",
+ ],
+
+ local_include_dirs: [
+ "include/filters",
+ ],
+
cflags: [
"-Wno-multichar",
"-Werror",
diff --git a/media/libstagefright/filters/ColorConvert.h b/media/libstagefright/filters/include/filters/ColorConvert.h
similarity index 100%
rename from media/libstagefright/filters/ColorConvert.h
rename to media/libstagefright/filters/include/filters/ColorConvert.h
diff --git a/media/libstagefright/filters/GraphicBufferListener.h b/media/libstagefright/filters/include/filters/GraphicBufferListener.h
similarity index 100%
rename from media/libstagefright/filters/GraphicBufferListener.h
rename to media/libstagefright/filters/include/filters/GraphicBufferListener.h
diff --git a/media/libstagefright/filters/IntrinsicBlurFilter.h b/media/libstagefright/filters/include/filters/IntrinsicBlurFilter.h
similarity index 100%
rename from media/libstagefright/filters/IntrinsicBlurFilter.h
rename to media/libstagefright/filters/include/filters/IntrinsicBlurFilter.h
diff --git a/media/libstagefright/filters/RSFilter.h b/media/libstagefright/filters/include/filters/RSFilter.h
similarity index 100%
rename from media/libstagefright/filters/RSFilter.h
rename to media/libstagefright/filters/include/filters/RSFilter.h
diff --git a/media/libstagefright/filters/SaturationFilter.h b/media/libstagefright/filters/include/filters/SaturationFilter.h
similarity index 100%
rename from media/libstagefright/filters/SaturationFilter.h
rename to media/libstagefright/filters/include/filters/SaturationFilter.h
diff --git a/media/libstagefright/filters/SimpleFilter.h b/media/libstagefright/filters/include/filters/SimpleFilter.h
similarity index 100%
rename from media/libstagefright/filters/SimpleFilter.h
rename to media/libstagefright/filters/include/filters/SimpleFilter.h
diff --git a/media/libstagefright/filters/ZeroFilter.h b/media/libstagefright/filters/include/filters/ZeroFilter.h
similarity index 100%
rename from media/libstagefright/filters/ZeroFilter.h
rename to media/libstagefright/filters/include/filters/ZeroFilter.h
diff --git a/media/libstagefright/foundation/AMessage.cpp b/media/libstagefright/foundation/AMessage.cpp
index c2114b3..5c99cc9 100644
--- a/media/libstagefright/foundation/AMessage.cpp
+++ b/media/libstagefright/foundation/AMessage.cpp
@@ -33,7 +33,7 @@
#include <media/stagefright/foundation/hexdump.h>
-#if !defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
+#if defined(__ANDROID__) && !defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
#include <binder/Parcel.h>
#endif
@@ -659,7 +659,7 @@
return s;
}
-#if !defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
+#if defined(__ANDROID__) && !defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
// static
sp<AMessage> AMessage::FromParcel(const Parcel &parcel, size_t maxNestingLevel) {
int32_t what = parcel.readInt32();
@@ -825,7 +825,7 @@
}
}
}
-#endif // !defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
+#endif // defined(__ANDROID__) && !defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
sp<AMessage> AMessage::changesFrom(const sp<const AMessage> &other, bool deep) const {
if (other == NULL) {
diff --git a/media/libstagefright/foundation/AString.cpp b/media/libstagefright/foundation/AString.cpp
index b1ed077..a5e0ff8 100644
--- a/media/libstagefright/foundation/AString.cpp
+++ b/media/libstagefright/foundation/AString.cpp
@@ -27,7 +27,7 @@
#include "ADebug.h"
#include "AString.h"
-#if !defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
+#if defined(__ANDROID__) && !defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
#include <binder/Parcel.h>
#endif
@@ -365,7 +365,7 @@
return !strcasecmp(mData + mSize - suffixLen, suffix);
}
-#if !defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
+#if defined(__ANDROID__) && !defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
// static
AString AString::FromParcel(const Parcel &parcel) {
size_t size = static_cast<size_t>(parcel.readInt32());
@@ -380,7 +380,7 @@
}
return err;
}
-#endif // !defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
+#endif // defined(__ANDROID__) && !defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
AString AStringPrintf(const char *format, ...) {
va_list ap;
diff --git a/media/libstagefright/foundation/MetaData.cpp b/media/libstagefright/foundation/MetaData.cpp
index 7f48cfd..77913d5 100644
--- a/media/libstagefright/foundation/MetaData.cpp
+++ b/media/libstagefright/foundation/MetaData.cpp
@@ -28,7 +28,7 @@
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/MetaData.h>
-#if !defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
+#if defined(__ANDROID__) && !defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
#include <binder/Parcel.h>
#endif
@@ -48,7 +48,7 @@
MetaData::~MetaData() {
}
-#if !defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
+#if defined(__ANDROID__) && !defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
/* static */
sp<MetaData> MetaData::createFromParcel(const Parcel &parcel) {
diff --git a/media/libstagefright/foundation/MetaDataBase.cpp b/media/libstagefright/foundation/MetaDataBase.cpp
index 3f050ea..980eb22 100644
--- a/media/libstagefright/foundation/MetaDataBase.cpp
+++ b/media/libstagefright/foundation/MetaDataBase.cpp
@@ -28,7 +28,7 @@
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/MetaDataBase.h>
-#if !defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
+#if defined(__ANDROID__) && !defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
#include <binder/Parcel.h>
#endif
@@ -452,7 +452,7 @@
}
}
-#if !defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
+#if defined(__ANDROID__) && !defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
status_t MetaDataBase::writeToParcel(Parcel &parcel) {
status_t ret;
size_t numItems = mInternalData->mItems.size();
@@ -532,7 +532,7 @@
ALOGW("no metadata in parcel");
return UNKNOWN_ERROR;
}
-#endif // !defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
+#endif // defined(__ANDROID__) && !defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
} // namespace android
diff --git a/media/libstagefright/http/Android.bp b/media/libstagefright/http/Android.bp
index f4d6d99..f25318d 100644
--- a/media/libstagefright/http/Android.bp
+++ b/media/libstagefright/http/Android.bp
@@ -12,10 +12,8 @@
srcs: ["HTTPHelper.cpp"],
- include_dirs: [
- "frameworks/av/media/libstagefright",
- "frameworks/native/include/media/openmax",
- "frameworks/base/core/jni",
+ header_libs: [
+ "libstagefright_headers",
],
shared_libs: [
diff --git a/media/libstagefright/httplive/Android.bp b/media/libstagefright/httplive/Android.bp
index 7acf735..7e26bd6 100644
--- a/media/libstagefright/httplive/Android.bp
+++ b/media/libstagefright/httplive/Android.bp
@@ -28,10 +28,6 @@
"PlaylistFetcher.cpp",
],
- include_dirs: [
- "frameworks/native/include/media/openmax",
- ],
-
cflags: [
"-Werror",
"-Wall",
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 0d7cadd..09ca1c9 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -23,7 +23,7 @@
#include "M3UParser.h"
#include "PlaylistFetcher.h"
-#include <AnotherPacketSource.h>
+#include <mpeg2ts/AnotherPacketSource.h>
#include <cutils/properties.h>
#include <media/MediaHTTPService.h>
diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h
index ceea41d..ed38a2e 100644
--- a/media/libstagefright/httplive/LiveSession.h
+++ b/media/libstagefright/httplive/LiveSession.h
@@ -24,7 +24,7 @@
#include <utils/String8.h>
-#include <ATSParser.h>
+#include <mpeg2ts/ATSParser.h>
namespace android {
diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp
index 907b326..b339fd2 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.cpp
+++ b/media/libstagefright/httplive/PlaylistFetcher.cpp
@@ -25,8 +25,8 @@
#include "LiveSession.h"
#include "M3UParser.h"
#include <ID3.h>
-#include <AnotherPacketSource.h>
-#include <HlsSampleDecryptor.h>
+#include <mpeg2ts/AnotherPacketSource.h>
+#include <mpeg2ts/HlsSampleDecryptor.h>
#include <datasource/DataURISource.h>
#include <media/stagefright/foundation/ABitReader.h>
diff --git a/media/libstagefright/httplive/PlaylistFetcher.h b/media/libstagefright/httplive/PlaylistFetcher.h
index 2e28164..716df63 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.h
+++ b/media/libstagefright/httplive/PlaylistFetcher.h
@@ -21,7 +21,7 @@
#include <media/stagefright/foundation/AHandler.h>
#include <openssl/aes.h>
-#include <ATSParser.h>
+#include <mpeg2ts/ATSParser.h>
#include "LiveSession.h"
namespace android {
diff --git a/media/libstagefright/include/media/stagefright/MediaBuffer.h b/media/libstagefright/include/media/stagefright/MediaBuffer.h
index 2c03f27..f070aac 100644
--- a/media/libstagefright/include/media/stagefright/MediaBuffer.h
+++ b/media/libstagefright/include/media/stagefright/MediaBuffer.h
@@ -105,7 +105,6 @@
if (mMemory.get() == nullptr || mMemory->unsecurePointer() == nullptr) return 0;
int32_t remoteRefcount =
reinterpret_cast<SharedControl *>(mMemory->unsecurePointer())->getRemoteRefcount();
- // Sanity check so that remoteRefCount() is non-negative.
return remoteRefcount >= 0 ? remoteRefcount : 0; // do not allow corrupted data.
#else
return 0;
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
index 3a01925..656267c 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
@@ -684,6 +684,7 @@
}
constexpr char FEATURE_AdaptivePlayback[] = "adaptive-playback";
+constexpr char FEATURE_EncodingStatistics[] = "encoding-statistics";
constexpr char FEATURE_IntraRefresh[] = "intra-refresh";
constexpr char FEATURE_PartialFrame[] = "partial-frame";
constexpr char FEATURE_QpBounds[] = "qp-bounds";
@@ -737,6 +738,14 @@
constexpr int32_t COLOR_TRANSFER_SDR_VIDEO = 3;
constexpr int32_t COLOR_TRANSFER_ST2084 = 6;
+constexpr int32_t PICTURE_TYPE_I = 1;
+constexpr int32_t PICTURE_TYPE_P = 2;
+constexpr int32_t PICTURE_TYPE_B = 3;
+constexpr int32_t PICTURE_TYPE_UNKNOWN = 0;
+
+constexpr int32_t VIDEO_ENCODING_STATISTICS_LEVEL_1 = 1;
+constexpr int32_t VIDEO_ENCODING_STATISTICS_LEVEL_NONE = 0;
+
constexpr char KEY_AAC_DRC_ALBUM_MODE[] = "aac-drc-album-mode";
constexpr char KEY_AAC_DRC_ATTENUATION_FACTOR[] = "aac-drc-cut-level";
constexpr char KEY_AAC_DRC_BOOST_FACTOR[] = "aac-drc-boost-level";
@@ -795,6 +804,7 @@
constexpr char KEY_OPERATING_RATE[] = "operating-rate";
constexpr char KEY_OUTPUT_REORDER_DEPTH[] = "output-reorder-depth";
constexpr char KEY_PCM_ENCODING[] = "pcm-encoding";
+constexpr char KEY_PICTURE_TYPE[] = "picture_type";
constexpr char KEY_PIXEL_ASPECT_RATIO_HEIGHT[] = "sar-height";
constexpr char KEY_PIXEL_ASPECT_RATIO_WIDTH[] = "sar-width";
constexpr char KEY_PREPEND_HEADER_TO_SYNC_FRAMES[] = "prepend-sps-pps-to-idr-frames";
@@ -811,6 +821,8 @@
constexpr char KEY_TILE_HEIGHT[] = "tile-height";
constexpr char KEY_TILE_WIDTH[] = "tile-width";
constexpr char KEY_TRACK_ID[] = "track-id";
+constexpr char KEY_VIDEO_ENCODING_STATISTICS_LEVEL[] = "video-encoding-statistics-level";
+constexpr char KEY_VIDEO_QP_AVERAGE[] = "video-qp-average";
constexpr char KEY_VIDEO_QP_B_MAX[] = "video-qp-b-max";
constexpr char KEY_VIDEO_QP_B_MIN[] = "video-qp-b-min";
constexpr char KEY_VIDEO_QP_I_MAX[] = "video-qp-i-max";
diff --git a/media/libstagefright/MediaCodecListOverrides.h b/media/libstagefright/include/media/stagefright/MediaCodecListOverrides.h
similarity index 100%
rename from media/libstagefright/MediaCodecListOverrides.h
rename to media/libstagefright/include/media/stagefright/MediaCodecListOverrides.h
diff --git a/media/libstagefright/mpeg2ts/Android.bp b/media/libstagefright/mpeg2ts/Android.bp
index fbfa8cc..283df1e 100644
--- a/media/libstagefright/mpeg2ts/Android.bp
+++ b/media/libstagefright/mpeg2ts/Android.bp
@@ -54,16 +54,21 @@
"libstagefright_foundation_headers",
],
- export_include_dirs: ["."],
+ export_include_dirs: ["include"],
+
+ local_include_dirs: ["include/mpeg2ts"],
whole_static_libs: [
"libstagefright_metadatautils",
],
+}
+
+cc_defaults {
+ name: "libstagefright_mpeg2support_sdk_defaults",
+
min_sdk_version: "29",
-
host_supported: true,
-
target: {
darwin: {
enabled: false,
@@ -71,10 +76,19 @@
},
}
+cc_library_headers {
+ name: "libstagefright_mpeg2support_headers",
+ defaults: [
+ "libstagefright_mpeg2support_sdk_defaults",
+ ],
+ export_include_dirs: ["include"],
+}
+
cc_library_static {
name: "libstagefright_mpeg2support",
defaults: [
"libstagefright_mpeg2support_defaults",
+ "libstagefright_mpeg2support_sdk_defaults",
],
cflags: [
"-DENABLE_CRYPTO",
@@ -91,6 +105,7 @@
name: "libstagefright_mpeg2support_nocrypto",
defaults: [
"libstagefright_mpeg2support_defaults",
+ "libstagefright_mpeg2support_sdk_defaults",
],
apex_available: [
"com.android.media",
diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/include/mpeg2ts/ATSParser.h
similarity index 100%
rename from media/libstagefright/mpeg2ts/ATSParser.h
rename to media/libstagefright/mpeg2ts/include/mpeg2ts/ATSParser.h
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.h b/media/libstagefright/mpeg2ts/include/mpeg2ts/AnotherPacketSource.h
similarity index 100%
rename from media/libstagefright/mpeg2ts/AnotherPacketSource.h
rename to media/libstagefright/mpeg2ts/include/mpeg2ts/AnotherPacketSource.h
diff --git a/media/libstagefright/mpeg2ts/CasManager.h b/media/libstagefright/mpeg2ts/include/mpeg2ts/CasManager.h
similarity index 100%
rename from media/libstagefright/mpeg2ts/CasManager.h
rename to media/libstagefright/mpeg2ts/include/mpeg2ts/CasManager.h
diff --git a/media/libstagefright/mpeg2ts/ESQueue.h b/media/libstagefright/mpeg2ts/include/mpeg2ts/ESQueue.h
similarity index 100%
rename from media/libstagefright/mpeg2ts/ESQueue.h
rename to media/libstagefright/mpeg2ts/include/mpeg2ts/ESQueue.h
diff --git a/media/libstagefright/mpeg2ts/HlsSampleDecryptor.h b/media/libstagefright/mpeg2ts/include/mpeg2ts/HlsSampleDecryptor.h
similarity index 100%
rename from media/libstagefright/mpeg2ts/HlsSampleDecryptor.h
rename to media/libstagefright/mpeg2ts/include/mpeg2ts/HlsSampleDecryptor.h
diff --git a/media/libstagefright/mpeg2ts/SampleDecryptor.h b/media/libstagefright/mpeg2ts/include/mpeg2ts/SampleDecryptor.h
similarity index 100%
rename from media/libstagefright/mpeg2ts/SampleDecryptor.h
rename to media/libstagefright/mpeg2ts/include/mpeg2ts/SampleDecryptor.h
diff --git a/media/libstagefright/mpeg2ts/test/Mpeg2tsUnitTest.cpp b/media/libstagefright/mpeg2ts/test/Mpeg2tsUnitTest.cpp
index 7f25d78..9e24a99 100644
--- a/media/libstagefright/mpeg2ts/test/Mpeg2tsUnitTest.cpp
+++ b/media/libstagefright/mpeg2ts/test/Mpeg2tsUnitTest.cpp
@@ -26,9 +26,8 @@
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaDataBase.h>
#include <media/stagefright/foundation/AUtils.h>
-
-#include <ATSParser.h>
-#include <AnotherPacketSource.h>
+#include <mpeg2ts/AnotherPacketSource.h>
+#include <mpeg2ts/ATSParser.h>
#include "Mpeg2tsUnitTestEnvironment.h"
diff --git a/media/libstagefright/rtsp/AAMRAssembler.cpp b/media/libstagefright/rtsp/AAMRAssembler.cpp
index bb2a238..e773031 100644
--- a/media/libstagefright/rtsp/AAMRAssembler.cpp
+++ b/media/libstagefright/rtsp/AAMRAssembler.cpp
@@ -18,9 +18,8 @@
#define LOG_TAG "AAMRAssembler"
#include <utils/Log.h>
-#include "AAMRAssembler.h"
-
-#include "ARTPSource.h"
+#include <media/stagefright/rtsp/AAMRAssembler.h>
+#include <media/stagefright/rtsp/ARTPSource.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
diff --git a/media/libstagefright/rtsp/AAVCAssembler.cpp b/media/libstagefright/rtsp/AAVCAssembler.cpp
index 30cdbc9..2f516d5 100644
--- a/media/libstagefright/rtsp/AAVCAssembler.cpp
+++ b/media/libstagefright/rtsp/AAVCAssembler.cpp
@@ -18,9 +18,9 @@
#define LOG_TAG "AAVCAssembler"
#include <utils/Log.h>
-#include "AAVCAssembler.h"
+#include <media/stagefright/rtsp/AAVCAssembler.h>
-#include "ARTPSource.h"
+#include <media/stagefright/rtsp/ARTPSource.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
diff --git a/media/libstagefright/rtsp/AH263Assembler.cpp b/media/libstagefright/rtsp/AH263Assembler.cpp
index 3436e95..584b4de 100644
--- a/media/libstagefright/rtsp/AH263Assembler.cpp
+++ b/media/libstagefright/rtsp/AH263Assembler.cpp
@@ -17,9 +17,9 @@
#define LOG_TAG "AH263Assembler"
#include <utils/Log.h>
-#include "AH263Assembler.h"
+#include <media/stagefright/rtsp/AH263Assembler.h>
-#include "ARTPSource.h"
+#include <media/stagefright/rtsp/ARTPSource.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
diff --git a/media/libstagefright/rtsp/AHEVCAssembler.cpp b/media/libstagefright/rtsp/AHEVCAssembler.cpp
index b240339..bb42d1f 100644
--- a/media/libstagefright/rtsp/AHEVCAssembler.cpp
+++ b/media/libstagefright/rtsp/AHEVCAssembler.cpp
@@ -18,14 +18,14 @@
#define LOG_TAG "AHEVCAssembler"
#include <utils/Log.h>
-#include "AHEVCAssembler.h"
+#include <media/stagefright/rtsp/AHEVCAssembler.h>
-#include "ARTPSource.h"
+#include <media/stagefright/rtsp/ARTPSource.h>
+#include <HevcUtils.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <include/HevcUtils.h>
#include <media/stagefright/foundation/hexdump.h>
#include <stdint.h>
diff --git a/media/libstagefright/rtsp/AMPEG2TSAssembler.cpp b/media/libstagefright/rtsp/AMPEG2TSAssembler.cpp
index 0988774..2101de1 100644
--- a/media/libstagefright/rtsp/AMPEG2TSAssembler.cpp
+++ b/media/libstagefright/rtsp/AMPEG2TSAssembler.cpp
@@ -18,10 +18,10 @@
#define LOG_TAG "AMPEG2TSAssembler"
#include <utils/Log.h>
-#include "AMPEG2TSAssembler.h"
+#include <media/stagefright/rtsp/AMPEG2TSAssembler.h>
-#include "ARTPSource.h"
-#include "ASessionDescription.h"
+#include <media/stagefright/rtsp/ARTPSource.h>
+#include <media/stagefright/rtsp/ASessionDescription.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
diff --git a/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp b/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp
index 4302aee..0fc03ae 100644
--- a/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp
+++ b/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp
@@ -17,9 +17,9 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "AMPEG4AudioAssembler"
-#include "AMPEG4AudioAssembler.h"
+#include <media/stagefright/rtsp/AMPEG4AudioAssembler.h>
-#include "ARTPSource.h"
+#include <media/stagefright/rtsp/ARTPSource.h>
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/foundation/ABitReader.h>
diff --git a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp
index 7bd33c1..6b1d2a1 100644
--- a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp
+++ b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp
@@ -18,10 +18,10 @@
#define LOG_TAG "AMPEG4ElementaryAssembler"
#include <utils/Log.h>
-#include "AMPEG4ElementaryAssembler.h"
+#include <media/stagefright/rtsp/AMPEG4ElementaryAssembler.h>
-#include "ARTPSource.h"
-#include "ASessionDescription.h"
+#include <media/stagefright/rtsp/ARTPSource.h>
+#include <media/stagefright/rtsp/ASessionDescription.h>
#include <media/stagefright/foundation/ABitReader.h>
#include <media/stagefright/foundation/ABuffer.h>
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index 169df46..db63183 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -18,10 +18,9 @@
#define LOG_TAG "APacketSource"
#include <utils/Log.h>
-#include "APacketSource.h"
-
-#include "ARawAudioAssembler.h"
-#include "ASessionDescription.h"
+#include <media/stagefright/rtsp/APacketSource.h>
+#include <media/stagefright/rtsp/ARawAudioAssembler.h>
+#include <media/stagefright/rtsp/ASessionDescription.h>
#include <ctype.h>
diff --git a/media/libstagefright/rtsp/ARTPAssembler.cpp b/media/libstagefright/rtsp/ARTPAssembler.cpp
index 52aa3a0..b9869de 100644
--- a/media/libstagefright/rtsp/ARTPAssembler.cpp
+++ b/media/libstagefright/rtsp/ARTPAssembler.cpp
@@ -15,7 +15,7 @@
*/
#define LOG_TAG "ARTPAssembler"
-#include "ARTPAssembler.h"
+#include <media/stagefright/rtsp/ARTPAssembler.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
diff --git a/media/libstagefright/rtsp/ARTPConnection.cpp b/media/libstagefright/rtsp/ARTPConnection.cpp
index 0bd342a..5a8f471 100644
--- a/media/libstagefright/rtsp/ARTPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTPConnection.cpp
@@ -18,9 +18,9 @@
#define LOG_TAG "ARTPConnection"
#include <utils/Log.h>
-#include "ARTPConnection.h"
-#include "ARTPSource.h"
-#include "ASessionDescription.h"
+#include <media/stagefright/rtsp/ARTPConnection.h>
+#include <media/stagefright/rtsp/ARTPSource.h>
+#include <media/stagefright/rtsp/ASessionDescription.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
diff --git a/media/libstagefright/rtsp/ARTPSession.cpp b/media/libstagefright/rtsp/ARTPSession.cpp
index e5acb06..dae46f9 100644
--- a/media/libstagefright/rtsp/ARTPSession.cpp
+++ b/media/libstagefright/rtsp/ARTPSession.cpp
@@ -18,7 +18,10 @@
#define LOG_TAG "ARTPSession"
#include <utils/Log.h>
-#include "ARTPSession.h"
+#include <media/stagefright/rtsp/APacketSource.h>
+#include <media/stagefright/rtsp/ARTPConnection.h>
+#include <media/stagefright/rtsp/ARTPSession.h>
+#include <media/stagefright/rtsp/ASessionDescription.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -29,9 +32,6 @@
#include <arpa/inet.h>
#include <sys/socket.h>
-#include "APacketSource.h"
-#include "ARTPConnection.h"
-#include "ASessionDescription.h"
namespace android {
diff --git a/media/libstagefright/rtsp/ARTPSource.cpp b/media/libstagefright/rtsp/ARTPSource.cpp
index 38a370b..5f62b9d 100644
--- a/media/libstagefright/rtsp/ARTPSource.cpp
+++ b/media/libstagefright/rtsp/ARTPSource.cpp
@@ -18,17 +18,17 @@
#define LOG_TAG "ARTPSource"
#include <utils/Log.h>
-#include "ARTPSource.h"
+#include <media/stagefright/rtsp/ARTPSource.h>
-#include "AAMRAssembler.h"
-#include "AAVCAssembler.h"
-#include "AHEVCAssembler.h"
-#include "AH263Assembler.h"
-#include "AMPEG2TSAssembler.h"
-#include "AMPEG4AudioAssembler.h"
-#include "AMPEG4ElementaryAssembler.h"
-#include "ARawAudioAssembler.h"
-#include "ASessionDescription.h"
+#include <media/stagefright/rtsp/AAMRAssembler.h>
+#include <media/stagefright/rtsp/AAVCAssembler.h>
+#include <media/stagefright/rtsp/AHEVCAssembler.h>
+#include <media/stagefright/rtsp/AH263Assembler.h>
+#include <media/stagefright/rtsp/AMPEG2TSAssembler.h>
+#include <media/stagefright/rtsp/AMPEG4AudioAssembler.h>
+#include <media/stagefright/rtsp/AMPEG4ElementaryAssembler.h>
+#include <media/stagefright/rtsp/ARawAudioAssembler.h>
+#include <media/stagefright/rtsp/ASessionDescription.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
diff --git a/media/libstagefright/rtsp/ARTPWriter.cpp b/media/libstagefright/rtsp/ARTPWriter.cpp
index 11c7aeb..8990f0c 100644
--- a/media/libstagefright/rtsp/ARTPWriter.cpp
+++ b/media/libstagefright/rtsp/ARTPWriter.cpp
@@ -18,7 +18,7 @@
#define LOG_TAG "ARTPWriter"
#include <utils/Log.h>
-#include "ARTPWriter.h"
+#include <media/stagefright/rtsp/ARTPWriter.h>
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/foundation/ABuffer.h>
diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp
index c33bf3f..aab63a8 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTSPConnection.cpp
@@ -18,8 +18,8 @@
#define LOG_TAG "ARTSPConnection"
#include <utils/Log.h>
-#include "ARTSPConnection.h"
-#include "NetworkUtils.h"
+#include <media/stagefright/rtsp/ARTSPConnection.h>
+#include <media/stagefright/rtsp/NetworkUtils.h>
#include <datasource/HTTPBase.h>
#include <media/stagefright/foundation/ABuffer.h>
diff --git a/media/libstagefright/rtsp/ARawAudioAssembler.cpp b/media/libstagefright/rtsp/ARawAudioAssembler.cpp
index 167f7a4..9210af3 100644
--- a/media/libstagefright/rtsp/ARawAudioAssembler.cpp
+++ b/media/libstagefright/rtsp/ARawAudioAssembler.cpp
@@ -18,10 +18,10 @@
#define LOG_TAG "ARawAudioAssembler"
#include <utils/Log.h>
-#include "ARawAudioAssembler.h"
+#include <media/stagefright/rtsp/ARawAudioAssembler.h>
-#include "ARTPSource.h"
-#include "ASessionDescription.h"
+#include <media/stagefright/rtsp/ARTPSource.h>
+#include <media/stagefright/rtsp/ASessionDescription.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
diff --git a/media/libstagefright/rtsp/ASessionDescription.cpp b/media/libstagefright/rtsp/ASessionDescription.cpp
index 5b5b4b1..217eca7 100644
--- a/media/libstagefright/rtsp/ASessionDescription.cpp
+++ b/media/libstagefright/rtsp/ASessionDescription.cpp
@@ -18,7 +18,7 @@
#define LOG_TAG "ASessionDescription"
#include <utils/Log.h>
-#include "ASessionDescription.h"
+#include <media/stagefright/rtsp/ASessionDescription.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AString.h>
diff --git a/media/libstagefright/rtsp/Android.bp b/media/libstagefright/rtsp/Android.bp
index 34d1788..97d4abe 100644
--- a/media/libstagefright/rtsp/Android.bp
+++ b/media/libstagefright/rtsp/Android.bp
@@ -47,10 +47,9 @@
"libmedia",
],
- include_dirs: [
- "frameworks/av/media/libstagefright",
- "frameworks/native/include/media/openmax",
- "frameworks/native/include/android",
+ header_libs: [
+ "libstagefright_headers",
+ "libstagefright_rtsp_headers",
],
arch: {
@@ -73,6 +72,18 @@
},
}
+cc_library_headers {
+ name: "libstagefright_rtsp_headers",
+ export_include_dirs: ["include"],
+ vendor_available: true,
+ host_supported: true,
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+}
+
cc_library_static {
name: "libstagefright_rtsp",
diff --git a/media/libstagefright/rtsp/JitterCalculator.cpp b/media/libstagefright/rtsp/JitterCalculator.cpp
index 7e60be2..93afe9c 100644
--- a/media/libstagefright/rtsp/JitterCalculator.cpp
+++ b/media/libstagefright/rtsp/JitterCalculator.cpp
@@ -17,7 +17,7 @@
#define LOG_TAG "JitterCalc"
#include <utils/Log.h>
-#include "JitterCalculator.h"
+#include <media/stagefright/rtsp/JitterCalculator.h>
#include <stdlib.h>
diff --git a/media/libstagefright/rtsp/NetworkUtils.cpp b/media/libstagefright/rtsp/NetworkUtils.cpp
index c053be8..e8ec64d 100644
--- a/media/libstagefright/rtsp/NetworkUtils.cpp
+++ b/media/libstagefright/rtsp/NetworkUtils.cpp
@@ -20,7 +20,7 @@
#define LOG_TAG "NetworkUtils"
#include <utils/Log.h>
-#include "NetworkUtils.h"
+#include <media/stagefright/rtsp/NetworkUtils.h>
#include <cutils/qtaguid.h>
#include <NetdClient.h>
diff --git a/media/libstagefright/rtsp/NetworkUtilsForAppProc.cpp b/media/libstagefright/rtsp/NetworkUtilsForAppProc.cpp
index 662159c..30fc38a 100644
--- a/media/libstagefright/rtsp/NetworkUtilsForAppProc.cpp
+++ b/media/libstagefright/rtsp/NetworkUtilsForAppProc.cpp
@@ -18,7 +18,7 @@
#define LOG_TAG "NetworkUtils"
#include <utils/Log.h>
-#include "NetworkUtils.h"
+#include <media/stagefright/rtsp/NetworkUtils.h>
// NetworkUtils implementation for application process.
namespace android {
diff --git a/media/libstagefright/rtsp/QualManager.cpp b/media/libstagefright/rtsp/QualManager.cpp
index 37aa326..f1f8222 100644
--- a/media/libstagefright/rtsp/QualManager.cpp
+++ b/media/libstagefright/rtsp/QualManager.cpp
@@ -21,7 +21,7 @@
#include <sys/prctl.h>
#include <utils/Log.h>
-#include "QualManager.h"
+#include <media/stagefright/rtsp/QualManager.h>
namespace android {
diff --git a/media/libstagefright/rtsp/SDPLoader.cpp b/media/libstagefright/rtsp/SDPLoader.cpp
index e236267..8cd33cf 100644
--- a/media/libstagefright/rtsp/SDPLoader.cpp
+++ b/media/libstagefright/rtsp/SDPLoader.cpp
@@ -18,9 +18,10 @@
#define LOG_TAG "SDPLoader"
#include <utils/Log.h>
-#include "include/SDPLoader.h"
+// #include "include/SDPLoader.h"
+#include <media/stagefright/rtsp/SDPLoader.h>
-#include "ASessionDescription.h"
+#include <media/stagefright/rtsp/ASessionDescription.h>
#include <datasource/MediaHTTP.h>
#include <media/MediaHTTPConnection.h>
diff --git a/media/libstagefright/rtsp/UDPPusher.cpp b/media/libstagefright/rtsp/UDPPusher.cpp
index 5c685a1..4e812f5 100644
--- a/media/libstagefright/rtsp/UDPPusher.cpp
+++ b/media/libstagefright/rtsp/UDPPusher.cpp
@@ -18,7 +18,7 @@
#define LOG_TAG "UDPPusher"
#include <utils/Log.h>
-#include "UDPPusher.h"
+#include <media/stagefright/rtsp/UDPPusher.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
diff --git a/media/libstagefright/rtsp/AAMRAssembler.h b/media/libstagefright/rtsp/include/media/stagefright/rtsp/AAMRAssembler.h
similarity index 100%
rename from media/libstagefright/rtsp/AAMRAssembler.h
rename to media/libstagefright/rtsp/include/media/stagefright/rtsp/AAMRAssembler.h
diff --git a/media/libstagefright/rtsp/AAVCAssembler.h b/media/libstagefright/rtsp/include/media/stagefright/rtsp/AAVCAssembler.h
similarity index 100%
rename from media/libstagefright/rtsp/AAVCAssembler.h
rename to media/libstagefright/rtsp/include/media/stagefright/rtsp/AAVCAssembler.h
diff --git a/media/libstagefright/rtsp/AH263Assembler.h b/media/libstagefright/rtsp/include/media/stagefright/rtsp/AH263Assembler.h
similarity index 100%
rename from media/libstagefright/rtsp/AH263Assembler.h
rename to media/libstagefright/rtsp/include/media/stagefright/rtsp/AH263Assembler.h
diff --git a/media/libstagefright/rtsp/AHEVCAssembler.h b/media/libstagefright/rtsp/include/media/stagefright/rtsp/AHEVCAssembler.h
similarity index 100%
rename from media/libstagefright/rtsp/AHEVCAssembler.h
rename to media/libstagefright/rtsp/include/media/stagefright/rtsp/AHEVCAssembler.h
diff --git a/media/libstagefright/rtsp/AMPEG2TSAssembler.h b/media/libstagefright/rtsp/include/media/stagefright/rtsp/AMPEG2TSAssembler.h
similarity index 100%
rename from media/libstagefright/rtsp/AMPEG2TSAssembler.h
rename to media/libstagefright/rtsp/include/media/stagefright/rtsp/AMPEG2TSAssembler.h
diff --git a/media/libstagefright/rtsp/AMPEG4AudioAssembler.h b/media/libstagefright/rtsp/include/media/stagefright/rtsp/AMPEG4AudioAssembler.h
similarity index 100%
rename from media/libstagefright/rtsp/AMPEG4AudioAssembler.h
rename to media/libstagefright/rtsp/include/media/stagefright/rtsp/AMPEG4AudioAssembler.h
diff --git a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.h b/media/libstagefright/rtsp/include/media/stagefright/rtsp/AMPEG4ElementaryAssembler.h
similarity index 100%
rename from media/libstagefright/rtsp/AMPEG4ElementaryAssembler.h
rename to media/libstagefright/rtsp/include/media/stagefright/rtsp/AMPEG4ElementaryAssembler.h
diff --git a/media/libstagefright/rtsp/APacketSource.h b/media/libstagefright/rtsp/include/media/stagefright/rtsp/APacketSource.h
similarity index 100%
rename from media/libstagefright/rtsp/APacketSource.h
rename to media/libstagefright/rtsp/include/media/stagefright/rtsp/APacketSource.h
diff --git a/media/libstagefright/rtsp/ARTPAssembler.h b/media/libstagefright/rtsp/include/media/stagefright/rtsp/ARTPAssembler.h
similarity index 100%
rename from media/libstagefright/rtsp/ARTPAssembler.h
rename to media/libstagefright/rtsp/include/media/stagefright/rtsp/ARTPAssembler.h
diff --git a/media/libstagefright/rtsp/ARTPConnection.h b/media/libstagefright/rtsp/include/media/stagefright/rtsp/ARTPConnection.h
similarity index 100%
rename from media/libstagefright/rtsp/ARTPConnection.h
rename to media/libstagefright/rtsp/include/media/stagefright/rtsp/ARTPConnection.h
diff --git a/media/libstagefright/rtsp/ARTPSession.h b/media/libstagefright/rtsp/include/media/stagefright/rtsp/ARTPSession.h
similarity index 100%
rename from media/libstagefright/rtsp/ARTPSession.h
rename to media/libstagefright/rtsp/include/media/stagefright/rtsp/ARTPSession.h
diff --git a/media/libstagefright/rtsp/ARTPSource.h b/media/libstagefright/rtsp/include/media/stagefright/rtsp/ARTPSource.h
similarity index 100%
rename from media/libstagefright/rtsp/ARTPSource.h
rename to media/libstagefright/rtsp/include/media/stagefright/rtsp/ARTPSource.h
diff --git a/media/libstagefright/rtsp/ARTPWriter.h b/media/libstagefright/rtsp/include/media/stagefright/rtsp/ARTPWriter.h
similarity index 100%
rename from media/libstagefright/rtsp/ARTPWriter.h
rename to media/libstagefright/rtsp/include/media/stagefright/rtsp/ARTPWriter.h
diff --git a/media/libstagefright/rtsp/ARTSPConnection.h b/media/libstagefright/rtsp/include/media/stagefright/rtsp/ARTSPConnection.h
similarity index 100%
rename from media/libstagefright/rtsp/ARTSPConnection.h
rename to media/libstagefright/rtsp/include/media/stagefright/rtsp/ARTSPConnection.h
diff --git a/media/libstagefright/rtsp/ARawAudioAssembler.h b/media/libstagefright/rtsp/include/media/stagefright/rtsp/ARawAudioAssembler.h
similarity index 100%
rename from media/libstagefright/rtsp/ARawAudioAssembler.h
rename to media/libstagefright/rtsp/include/media/stagefright/rtsp/ARawAudioAssembler.h
diff --git a/media/libstagefright/rtsp/ASessionDescription.h b/media/libstagefright/rtsp/include/media/stagefright/rtsp/ASessionDescription.h
similarity index 100%
rename from media/libstagefright/rtsp/ASessionDescription.h
rename to media/libstagefright/rtsp/include/media/stagefright/rtsp/ASessionDescription.h
diff --git a/media/libstagefright/rtsp/JitterCalculator.h b/media/libstagefright/rtsp/include/media/stagefright/rtsp/JitterCalculator.h
similarity index 100%
rename from media/libstagefright/rtsp/JitterCalculator.h
rename to media/libstagefright/rtsp/include/media/stagefright/rtsp/JitterCalculator.h
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/include/media/stagefright/rtsp/MyHandler.h
similarity index 100%
rename from media/libstagefright/rtsp/MyHandler.h
rename to media/libstagefright/rtsp/include/media/stagefright/rtsp/MyHandler.h
diff --git a/media/libstagefright/rtsp/NetworkUtils.h b/media/libstagefright/rtsp/include/media/stagefright/rtsp/NetworkUtils.h
similarity index 100%
rename from media/libstagefright/rtsp/NetworkUtils.h
rename to media/libstagefright/rtsp/include/media/stagefright/rtsp/NetworkUtils.h
diff --git a/media/libstagefright/rtsp/QualManager.h b/media/libstagefright/rtsp/include/media/stagefright/rtsp/QualManager.h
similarity index 100%
rename from media/libstagefright/rtsp/QualManager.h
rename to media/libstagefright/rtsp/include/media/stagefright/rtsp/QualManager.h
diff --git a/media/libstagefright/include/SDPLoader.h b/media/libstagefright/rtsp/include/media/stagefright/rtsp/SDPLoader.h
similarity index 100%
rename from media/libstagefright/include/SDPLoader.h
rename to media/libstagefright/rtsp/include/media/stagefright/rtsp/SDPLoader.h
diff --git a/media/libstagefright/rtsp/TrafficRecorder.h b/media/libstagefright/rtsp/include/media/stagefright/rtsp/TrafficRecorder.h
similarity index 100%
rename from media/libstagefright/rtsp/TrafficRecorder.h
rename to media/libstagefright/rtsp/include/media/stagefright/rtsp/TrafficRecorder.h
diff --git a/media/libstagefright/rtsp/UDPPusher.h b/media/libstagefright/rtsp/include/media/stagefright/rtsp/UDPPusher.h
similarity index 100%
rename from media/libstagefright/rtsp/UDPPusher.h
rename to media/libstagefright/rtsp/include/media/stagefright/rtsp/UDPPusher.h
diff --git a/media/libstagefright/rtsp/VideoSource.h b/media/libstagefright/rtsp/include/media/stagefright/rtsp/VideoSource.h
similarity index 100%
rename from media/libstagefright/rtsp/VideoSource.h
rename to media/libstagefright/rtsp/include/media/stagefright/rtsp/VideoSource.h
diff --git a/media/libstagefright/rtsp/rtp_test.cpp b/media/libstagefright/rtsp/rtp_test.cpp
index 4590699..1ae4a09 100644
--- a/media/libstagefright/rtsp/rtp_test.cpp
+++ b/media/libstagefright/rtsp/rtp_test.cpp
@@ -27,9 +27,9 @@
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/SimpleDecodingSource.h>
-#include "ARTPSession.h"
-#include "ASessionDescription.h"
-#include "UDPPusher.h"
+#include <media/stagefright/rtsp/ARTPSession.h>
+#include <media/stagefright/rtsp/ASessionDescription.h>
+#include <media/stagefright/rtsp/UDPPusher.h>
using namespace android;
diff --git a/media/libstagefright/tests/Android.bp b/media/libstagefright/tests/Android.bp
index a799a13..e6b67ce 100644
--- a/media/libstagefright/tests/Android.bp
+++ b/media/libstagefright/tests/Android.bp
@@ -32,11 +32,6 @@
"liblog",
],
- include_dirs: [
- "frameworks/av/media/libstagefright",
- "frameworks/av/media/libstagefright/include",
- ],
-
cflags: [
"-Werror",
"-Wall",
diff --git a/media/libstagefright/tests/MediaCodecListOverrides_test.cpp b/media/libstagefright/tests/MediaCodecListOverrides_test.cpp
index 0c22a42..20737db 100644
--- a/media/libstagefright/tests/MediaCodecListOverrides_test.cpp
+++ b/media/libstagefright/tests/MediaCodecListOverrides_test.cpp
@@ -20,11 +20,10 @@
#include <gtest/gtest.h>
-#include "MediaCodecListOverrides.h"
-
#include <media/MediaCodecInfo.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/MediaCodecList.h>
+#include <media/stagefright/MediaCodecListOverrides.h>
#include <vector>
diff --git a/media/libstagefright/tests/fuzzers/Android.bp b/media/libstagefright/tests/fuzzers/Android.bp
index 250ffb9..2bcfd67 100644
--- a/media/libstagefright/tests/fuzzers/Android.bp
+++ b/media/libstagefright/tests/fuzzers/Android.bp
@@ -32,9 +32,6 @@
"liblog",
"media_permission-aidl-cpp",
],
- include_dirs: [
- "frameworks/av/media/libstagefright",
- ],
}
cc_fuzz {
@@ -86,6 +83,9 @@
],
dictionary: "dictionaries/formats.dict",
defaults: ["libstagefright_fuzzer_defaults"],
+ header_libs: [
+ "libstagefright_webm_headers",
+ ],
static_libs: [
"libdatasource",
],
diff --git a/media/libstagefright/tests/fuzzers/FrameDecoderFuzzer.cpp b/media/libstagefright/tests/fuzzers/FrameDecoderFuzzer.cpp
index b346718..4218d2d 100644
--- a/media/libstagefright/tests/fuzzers/FrameDecoderFuzzer.cpp
+++ b/media/libstagefright/tests/fuzzers/FrameDecoderFuzzer.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "include/FrameDecoder.h"
+#include <FrameDecoder.h>
#include <fuzzer/FuzzedDataProvider.h>
#include <media/IMediaSource.h>
#include <media/stagefright/MetaData.h>
diff --git a/media/libstagefright/tests/fuzzers/FuzzerMediaUtility.cpp b/media/libstagefright/tests/fuzzers/FuzzerMediaUtility.cpp
index 810ae95..d94c8ff 100644
--- a/media/libstagefright/tests/fuzzers/FuzzerMediaUtility.cpp
+++ b/media/libstagefright/tests/fuzzers/FuzzerMediaUtility.cpp
@@ -23,7 +23,8 @@
#include <media/stagefright/OggWriter.h>
#include "MediaMimeTypes.h"
-#include "webm/WebmWriter.h"
+
+#include <webm/WebmWriter.h>
namespace android {
std::string genMimeType(FuzzedDataProvider *dataProvider) {
@@ -121,4 +122,4 @@
}
return writer;
}
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/media/libstagefright/tests/writer/WriterTest.cpp b/media/libstagefright/tests/writer/WriterTest.cpp
index 398c592..d170e7c 100644
--- a/media/libstagefright/tests/writer/WriterTest.cpp
+++ b/media/libstagefright/tests/writer/WriterTest.cpp
@@ -36,7 +36,7 @@
#include <media/stagefright/MPEG2TSWriter.h>
#include <media/stagefright/MPEG4Writer.h>
#include <media/stagefright/OggWriter.h>
-#include <WebmWriter.h>
+#include <webm/WebmWriter.h>
#include "WriterTestEnvironment.h"
#include "WriterUtility.h"
diff --git a/media/libstagefright/timedtext/Android.bp b/media/libstagefright/timedtext/Android.bp
index 6590ef7..619e06b 100644
--- a/media/libstagefright/timedtext/Android.bp
+++ b/media/libstagefright/timedtext/Android.bp
@@ -35,8 +35,16 @@
cfi: true,
},
- include_dirs: [
- "frameworks/av/media/libstagefright",
+ export_include_dirs: [
+ "include",
+ ],
+
+ local_include_dirs: [
+ "include/timedtext",
+ ],
+
+ header_libs: [
+ "libstagefright_headers",
],
shared_libs: ["libmedia"],
diff --git a/media/libstagefright/timedtext/TextDescriptions.h b/media/libstagefright/timedtext/include/timedtext/TextDescriptions.h
similarity index 100%
rename from media/libstagefright/timedtext/TextDescriptions.h
rename to media/libstagefright/timedtext/include/timedtext/TextDescriptions.h
diff --git a/media/libstagefright/timedtext/test/Android.bp b/media/libstagefright/timedtext/test/Android.bp
index 0b632bf..58c68ef 100644
--- a/media/libstagefright/timedtext/test/Android.bp
+++ b/media/libstagefright/timedtext/test/Android.bp
@@ -39,8 +39,8 @@
"libstagefright_foundation",
],
- include_dirs: [
- "frameworks/av/media/libstagefright",
+ header_libs: [
+ "libstagefright_headers",
],
shared_libs: [
diff --git a/media/libstagefright/timedtext/test/TimedTextUnitTest.cpp b/media/libstagefright/timedtext/test/TimedTextUnitTest.cpp
index d85ae39..f934b54 100644
--- a/media/libstagefright/timedtext/test/TimedTextUnitTest.cpp
+++ b/media/libstagefright/timedtext/test/TimedTextUnitTest.cpp
@@ -27,7 +27,7 @@
#include <media/stagefright/foundation/AString.h>
#include <media/stagefright/foundation/ByteUtils.h>
-#include "timedtext/TextDescriptions.h"
+#include <timedtext/TextDescriptions.h>
#include "TimedTextTestEnvironment.h"
diff --git a/media/libstagefright/webm/Android.bp b/media/libstagefright/webm/Android.bp
index 4209aea..9d5f430 100644
--- a/media/libstagefright/webm/Android.bp
+++ b/media/libstagefright/webm/Android.bp
@@ -33,7 +33,11 @@
"WebmWriter.cpp",
],
- export_include_dirs: ["."],
+ local_include_dirs: [
+ "include/webm",
+ ],
+
+ export_include_dirs: ["include"],
shared_libs: [
"libdatasource",
@@ -49,3 +53,16 @@
"media_ndk_headers",
],
}
+
+
+cc_library_headers {
+ name: "libstagefright_webm_headers",
+ export_include_dirs: ["include"],
+
+ host_supported: true,
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+}
diff --git a/media/libstagefright/webm/EbmlUtil.h b/media/libstagefright/webm/include/webm/EbmlUtil.h
similarity index 100%
rename from media/libstagefright/webm/EbmlUtil.h
rename to media/libstagefright/webm/include/webm/EbmlUtil.h
diff --git a/media/libstagefright/webm/LinkedBlockingQueue.h b/media/libstagefright/webm/include/webm/LinkedBlockingQueue.h
similarity index 100%
rename from media/libstagefright/webm/LinkedBlockingQueue.h
rename to media/libstagefright/webm/include/webm/LinkedBlockingQueue.h
diff --git a/media/libstagefright/webm/WebmConstants.h b/media/libstagefright/webm/include/webm/WebmConstants.h
similarity index 100%
rename from media/libstagefright/webm/WebmConstants.h
rename to media/libstagefright/webm/include/webm/WebmConstants.h
diff --git a/media/libstagefright/webm/WebmElement.h b/media/libstagefright/webm/include/webm/WebmElement.h
similarity index 100%
rename from media/libstagefright/webm/WebmElement.h
rename to media/libstagefright/webm/include/webm/WebmElement.h
diff --git a/media/libstagefright/webm/WebmFrame.h b/media/libstagefright/webm/include/webm/WebmFrame.h
similarity index 100%
rename from media/libstagefright/webm/WebmFrame.h
rename to media/libstagefright/webm/include/webm/WebmFrame.h
diff --git a/media/libstagefright/webm/WebmFrameThread.h b/media/libstagefright/webm/include/webm/WebmFrameThread.h
similarity index 100%
rename from media/libstagefright/webm/WebmFrameThread.h
rename to media/libstagefright/webm/include/webm/WebmFrameThread.h
diff --git a/media/libstagefright/webm/WebmWriter.h b/media/libstagefright/webm/include/webm/WebmWriter.h
similarity index 100%
rename from media/libstagefright/webm/WebmWriter.h
rename to media/libstagefright/webm/include/webm/WebmWriter.h
diff --git a/media/libstagefright/webm/tests/Android.bp b/media/libstagefright/webm/tests/Android.bp
index 4443766..629ee47 100644
--- a/media/libstagefright/webm/tests/Android.bp
+++ b/media/libstagefright/webm/tests/Android.bp
@@ -31,8 +31,8 @@
"WebmFrameThreadUnitTest.cpp",
],
- include_dirs: [
- "frameworks/av/media/libstagefright",
+ header_libs: [
+ "libstagefright_headers",
],
static_libs: [
diff --git a/media/libstagefright/writer_fuzzers/Android.bp b/media/libstagefright/writer_fuzzers/Android.bp
index a33b888..b81f27e 100644
--- a/media/libstagefright/writer_fuzzers/Android.bp
+++ b/media/libstagefright/writer_fuzzers/Android.bp
@@ -119,7 +119,7 @@
"libstagefright_webm",
"libdatasource",
],
- include_dirs: [
- "frameworks/av/media/libstagefright",
+ header_libs: [
+ "libstagefright_headers",
],
}
diff --git a/media/mediaserver/Android.bp b/media/mediaserver/Android.bp
index e25658f..537df76 100644
--- a/media/mediaserver/Android.bp
+++ b/media/mediaserver/Android.bp
@@ -47,11 +47,6 @@
"libregistermsext",
],
- include_dirs: [
- "frameworks/av/media/libmediaplayerservice",
- "frameworks/av/services/mediaresourcemanager",
- ],
-
// By default mediaserver runs in 32-bit to save memory, except
// on 64-bit-only lunch targets.
// ****************************************************************
diff --git a/media/mediaserver/main_mediaserver.cpp b/media/mediaserver/main_mediaserver.cpp
index 58e2d2a..026847a 100644
--- a/media/mediaserver/main_mediaserver.cpp
+++ b/media/mediaserver/main_mediaserver.cpp
@@ -25,9 +25,8 @@
#include <utils/Log.h>
#include "RegisterExtensions.h"
-// from LOCAL_C_INCLUDES
-#include "MediaPlayerService.h"
-#include "ResourceManagerService.h"
+#include <MediaPlayerService.h>
+#include <ResourceManagerService.h>
using namespace android;
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index 8d527e9..6c5e6cb 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -167,7 +167,7 @@
stubs: {
symbol_file: "libmediandk.map.txt",
versions: ["29"],
- },
+ }
}
cc_library {
diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp
index 6e9945d..59c1103 100644
--- a/media/ndk/NdkMediaDrm.cpp
+++ b/media/ndk/NdkMediaDrm.cpp
@@ -97,6 +97,8 @@
List<idvec_t> mIds;
KeyedVector<String8, String8> mQueryResults;
Vector<uint8_t> mKeyRequest;
+ String8 mDefaultUrl;
+ AMediaDrmKeyRequestType mkeyRequestType;
Vector<uint8_t> mProvisionRequest;
String8 mProvisionUrl;
String8 mPropertyString;
@@ -416,6 +418,21 @@
const AMediaDrmKeyValue *optionalParameters, size_t numOptionalParameters,
const uint8_t **keyRequest, size_t *keyRequestSize) {
+ return AMediaDrm_getKeyRequestWithDefaultUrlAndType(mObj,
+ scope, init, initSize, mimeType, keyType, optionalParameters,
+ numOptionalParameters, keyRequest,
+ keyRequestSize, NULL, NULL);
+}
+
+EXPORT
+media_status_t AMediaDrm_getKeyRequestWithDefaultUrlAndType(AMediaDrm *mObj,
+ const AMediaDrmScope *scope, const uint8_t *init, size_t initSize,
+ const char *mimeType, AMediaDrmKeyType keyType,
+ const AMediaDrmKeyValue *optionalParameters,
+ size_t numOptionalParameters, const uint8_t **keyRequest,
+ size_t *keyRequestSize, const char **defaultUrl,
+ AMediaDrmKeyRequestType *keyRequestType) {
+
if (!mObj || mObj->mDrm == NULL) {
return AMEDIA_ERROR_INVALID_OBJECT;
}
@@ -449,18 +466,43 @@
mdOptionalParameters.add(String8(optionalParameters[i].mKey),
String8(optionalParameters[i].mValue));
}
- String8 defaultUrl;
- DrmPlugin::KeyRequestType keyRequestType;
+
+ DrmPlugin::KeyRequestType requestType;
mObj->mKeyRequest.clear();
status_t status = mObj->mDrm->getKeyRequest(*iter, mdInit, String8(mimeType),
- mdKeyType, mdOptionalParameters, mObj->mKeyRequest, defaultUrl,
- &keyRequestType);
+ mdKeyType, mdOptionalParameters, mObj->mKeyRequest, mObj->mDefaultUrl,
+ &requestType);
if (status != OK) {
return translateStatus(status);
} else {
*keyRequest = mObj->mKeyRequest.array();
*keyRequestSize = mObj->mKeyRequest.size();
+ if (defaultUrl != NULL)
+ *defaultUrl = mObj->mDefaultUrl.string();
+ switch(requestType) {
+ case DrmPlugin::kKeyRequestType_Initial:
+ mObj->mkeyRequestType = KEY_REQUEST_TYPE_INITIAL;
+ break;
+ case DrmPlugin::kKeyRequestType_Renewal:
+ mObj->mkeyRequestType = KEY_REQUEST_TYPE_RENEWAL;
+ break;
+ case DrmPlugin::kKeyRequestType_Release:
+ mObj->mkeyRequestType = KEY_REQUEST_TYPE_RELEASE;
+ break;
+ case DrmPlugin::kKeyRequestType_None:
+ mObj->mkeyRequestType = KEY_REQUEST_TYPE_NONE;
+ break;
+ case DrmPlugin::kKeyRequestType_Update:
+ mObj->mkeyRequestType = KEY_REQUEST_TYPE_UPDATE;
+ break;
+ default:
+ return AMEDIA_ERROR_UNKNOWN;
+ }
+
+ if (keyRequestType != NULL)
+ *keyRequestType = mObj->mkeyRequestType;
}
+
return AMEDIA_OK;
}
diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp
index 69ab242..923453a 100644
--- a/media/ndk/NdkMediaFormat.cpp
+++ b/media/ndk/NdkMediaFormat.cpp
@@ -361,6 +361,7 @@
"mpegh-reference-channel-layout";
EXPORT const char* AMEDIAFORMAT_KEY_OPERATING_RATE = "operating-rate";
EXPORT const char* AMEDIAFORMAT_KEY_PCM_ENCODING = "pcm-encoding";
+EXPORT const char* AMEDIAFORMAT_KEY_PICTURE_TYPE = "picture-type";
EXPORT const char* AMEDIAFORMAT_KEY_PRIORITY = "priority";
EXPORT const char* AMEDIAFORMAT_KEY_PROFILE = "profile";
EXPORT const char* AMEDIAFORMAT_KEY_PCM_BIG_ENDIAN = "pcm-big-endian";
@@ -394,6 +395,9 @@
EXPORT const char* AMEDIAFORMAT_KEY_TRACK_ID = "track-id";
EXPORT const char* AMEDIAFORMAT_KEY_TRACK_INDEX = "track-index";
EXPORT const char* AMEDIAFORMAT_KEY_VALID_SAMPLES = "valid-samples";
+EXPORT const char* AMEDIAFORMAT_KEY_VIDEO_ENCODING_STATISTICS_LEVEL =
+ "video-encoding-statistics-level";
+EXPORT const char* AMEDIAFORMAT_KEY_VIDEO_QP_AVERAGE = "video-qp-average";
EXPORT const char* AMEDIAFORMAT_VIDEO_QP_B_MAX = "video-qp-b-max";
EXPORT const char* AMEDIAFORMAT_VIDEO_QP_B_MIN = "video-qp-b-min";
EXPORT const char* AMEDIAFORMAT_VIDEO_QP_I_MAX = "video-qp-i-max";
diff --git a/media/ndk/include/media/NdkMediaDrm.h b/media/ndk/include/media/NdkMediaDrm.h
index 849a8f9..4eca3d7 100644
--- a/media/ndk/include/media/NdkMediaDrm.h
+++ b/media/ndk/include/media/NdkMediaDrm.h
@@ -112,6 +112,41 @@
} AMediaDrmKeyType;
/**
+ * Introduced in API 33.
+ */
+typedef enum AMediaDrmKeyRequestType : int32_t {
+ /**
+ * Key request type is initial license request.
+ * An initial license request is necessary to load keys.
+ */
+ KEY_REQUEST_TYPE_INITIAL,
+
+ /**
+ * Key request type is license renewal.
+ * A renewal license request is necessary to prevent the keys from expiring.
+ */
+ KEY_REQUEST_TYPE_RENEWAL,
+
+ /**
+ * Key request type is license release.
+ * A license release request indicates that keys are removed.
+ */
+ KEY_REQUEST_TYPE_RELEASE,
+
+ /**
+ * Keys are already loaded and are available for use. No license request is necessary, and
+ * no key request data is returned.
+ */
+ KEY_REQUEST_TYPE_NONE,
+
+ /**
+ * Keys have been loaded but an additional license request is needed
+ * to update their values.
+ */
+ KEY_REQUEST_TYPE_UPDATE
+} AMediaDrmKeyRequestType;
+
+/**
* Data type containing {key, value} pair
*/
typedef struct AMediaDrmKeyValuePair {
@@ -248,7 +283,10 @@
* to obtain or release keys used to decrypt encrypted content.
* AMediaDrm_getKeyRequest is used to obtain an opaque key request byte array that
* is delivered to the license server. The opaque key request byte array is
- * returned in KeyRequest.data.
+ * returned in *keyRequest and the number of bytes in the request is
+ * returned in *keyRequestSize.
+ * This API has same functionality as AMediaDrm_getKeyRequestWithDefaultUrlAndType()
+ * when defaultUrl and keyRequestType are passed in as NULL.
*
* After the app has received the key request response from the server,
* it should deliver to the response to the DRM engine plugin using the method
@@ -280,11 +318,14 @@
* by the caller
*
* On exit:
+ * If this returns AMEDIA_OK,
* 1. The keyRequest pointer will reference the opaque key request data. It
* will reside in memory owned by the AMediaDrm object, and will remain
- * accessible until the next call to AMediaDrm_getKeyRequest or until the
+ * accessible until the next call to AMediaDrm_getKeyRequest
+ * or AMediaDrm_getKeyRequestWithDefaultUrlAndType or until the
* MediaDrm object is released.
* 2. keyRequestSize will be set to the size of the request
+ * If this does not return AMEDIA_OK, value of these parameters should not be used.
*
* Returns MEDIADRM_NOT_PROVISIONED_ERROR if reprovisioning is needed, due to a
* problem with the device certificate.
@@ -297,6 +338,72 @@
const uint8_t **keyRequest, size_t *keyRequestSize) __INTRODUCED_IN(21);
/**
+ * A key request/response exchange occurs between the app and a license server
+ * to obtain or release keys used to decrypt encrypted content.
+ * AMediaDrm_getKeyRequest is used to obtain an opaque key request byte array that
+ * is delivered to the license server. The opaque key request byte array is
+ * returned in *keyRequest and the number of bytes in the request is
+ * returned in *keyRequestSize.
+ *
+ * After the app has received the key request response from the server,
+ * it should deliver to the response to the DRM engine plugin using the method
+ * AMediaDrm_provideKeyResponse.
+ *
+ * scope may be a sessionId or a keySetId, depending on the specified keyType.
+ * When the keyType is KEY_TYPE_STREAMING or KEY_TYPE_OFFLINE, scope should be set
+ * to the sessionId the keys will be provided to. When the keyType is
+ * KEY_TYPE_RELEASE, scope should be set to the keySetId of the keys being released.
+ * Releasing keys from a device invalidates them for all sessions.
+ *
+ * init container-specific data, its meaning is interpreted based on the mime type
+ * provided in the mimeType parameter. It could contain, for example, the content
+ * ID, key ID or other data obtained from the content metadata that is required in
+ * generating the key request. init may be null when keyType is KEY_TYPE_RELEASE.
+ *
+ * initSize is the number of bytes of initData
+ *
+ * mimeType identifies the mime type of the content.
+ *
+ * keyType specifes the type of the request. The request may be to acquire keys for
+ * streaming or offline content, or to release previously acquired keys, which are
+ * identified by a keySetId.
+ *
+ * optionalParameters are included in the key request message to allow a client
+ * application to provide additional message parameters to the server.
+ *
+ * numOptionalParameters indicates the number of optional parameters provided
+ * by the caller
+ *
+ * On exit:
+ * If this returns AMEDIA_OK,
+ * 1. The keyRequest pointer will reference the opaque key request data. It
+ * will reside in memory owned by the AMediaDrm object, and will remain
+ * accessible until the next call to either AMediaDrm_getKeyRequest
+ * or AMediaDrm_getKeyRequestWithDefaultUrlAndType or until the
+ * MediaDrm object is released.
+ * 2. keyRequestSize will be set to the size of the request.
+ * 3. defaultUrl will be set to the recommended URL to deliver the key request.
+ * The defaultUrl pointer will reference a NULL terminated URL string.
+ * It will be UTF-8 encoded and have same lifetime with the key request data
+ * KeyRequest pointer references to. Passing in NULL means you don't need it
+ * to be reported.
+ * 4. keyRequestType will be set to the key request type. Passing in NULL means
+* you don't need it to be reported.
+ *
+ * Returns MEDIADRM_NOT_PROVISIONED_ERROR if reprovisioning is needed, due to a
+ * problem with the device certificate.
+ *
+ * Available since API level 33.
+ */
+media_status_t AMediaDrm_getKeyRequestWithDefaultUrlAndType(AMediaDrm *,
+ const AMediaDrmScope *scope, const uint8_t *init, size_t initSize,
+ const char *mimeType, AMediaDrmKeyType keyType,
+ const AMediaDrmKeyValue *optionalParameters,
+ size_t numOptionalParameters, const uint8_t **keyRequest,
+ size_t *keyRequestSize, const char **defaultUrl,
+ AMediaDrmKeyRequestType *keyRequestType) __INTRODUCED_IN(__ANDROID_API_T__);
+
+/**
* A key response is received from the license server by the app, then it is
* provided to the DRM engine plugin using provideKeyResponse. When the
* response is for an offline key request, a keySetId is returned that can be
diff --git a/media/ndk/include/media/NdkMediaFormat.h b/media/ndk/include/media/NdkMediaFormat.h
index 2d2fcc0..2195657 100644
--- a/media/ndk/include/media/NdkMediaFormat.h
+++ b/media/ndk/include/media/NdkMediaFormat.h
@@ -311,6 +311,10 @@
extern const char* AMEDIAFORMAT_KEY_LAST_SAMPLE_INDEX_IN_CHUNK __INTRODUCED_IN(31);
extern const char* AMEDIAFORMAT_KEY_SAMPLE_TIME_BEFORE_APPEND __INTRODUCED_IN(31);
+extern const char* AMEDIAFORMAT_KEY_PICTURE_TYPE __INTRODUCED_IN(33);
+extern const char* AMEDIAFORMAT_KEY_VIDEO_ENCODING_STATISTICS_LEVEL __INTRODUCED_IN(33);
+extern const char* AMEDIAFORMAT_KEY_VIDEO_QP_AVERAGE __INTRODUCED_IN(33);
+
extern const char* AMEDIAFORMAT_VIDEO_QP_B_MAX __INTRODUCED_IN(31);
extern const char* AMEDIAFORMAT_VIDEO_QP_B_MIN __INTRODUCED_IN(31);
extern const char* AMEDIAFORMAT_VIDEO_QP_I_MAX __INTRODUCED_IN(31);
diff --git a/media/ndk/libmediandk.map.txt b/media/ndk/libmediandk.map.txt
index 6f275c7..b228945 100644
--- a/media/ndk/libmediandk.map.txt
+++ b/media/ndk/libmediandk.map.txt
@@ -229,6 +229,7 @@
AMediaDrm_decrypt;
AMediaDrm_encrypt;
AMediaDrm_getKeyRequest;
+ AMediaDrm_getKeyRequestWithDefaultUrlAndType; # introduced=Tiramisu
AMediaDrm_getPropertyByteArray;
AMediaDrm_getPropertyString;
AMediaDrm_getProvisionRequest;
diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp
index 3ee7626..1ab5bc1 100644
--- a/media/utils/ServiceUtilities.cpp
+++ b/media/utils/ServiceUtilities.cpp
@@ -220,6 +220,17 @@
return ok;
}
+bool accessUltrasoundAllowed(const AttributionSourceState& attributionSource) {
+ uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid));
+ uid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(attributionSource.pid));
+ if (isAudioServerOrRootUid(uid)) return true;
+ static const String16 sAccessUltrasound(
+ "android.permission.ACCESS_ULTRASOUND");
+ bool ok = PermissionCache::checkPermission(sAccessUltrasound, pid, uid);
+ if (!ok) ALOGE("Request requires android.permission.ACCESS_ULTRASOUND");
+ return ok;
+}
+
bool captureHotwordAllowed(const AttributionSourceState& attributionSource) {
// CAPTURE_AUDIO_HOTWORD permission implies RECORD_AUDIO permission
bool ok = recordingAllowed(attributionSource);
@@ -316,7 +327,7 @@
// IMPORTANT: Use PermissionCache - not a runtime permission and may not change.
bool ok = PermissionCache::checkPermission(sCallAudioInterception, pid, uid);
- if (!ok) ALOGE("%s(): android.permission.CALL_AUDIO_INTERCEPTION denied for uid %d",
+ if (!ok) ALOGV("%s(): android.permission.CALL_AUDIO_INTERCEPTION denied for uid %d",
__func__, uid);
return ok;
}
diff --git a/media/utils/fuzzers/Android.bp b/media/utils/fuzzers/Android.bp
index c4dc24f..d26e6c2 100644
--- a/media/utils/fuzzers/Android.bp
+++ b/media/utils/fuzzers/Android.bp
@@ -32,11 +32,6 @@
"bionic_libc_platform_headers",
"libmedia_headers",
],
-
- include_dirs: [
- // For DEBUGGER_SIGNAL
- "system/core/debuggerd/include",
- ],
}
cc_fuzz {
diff --git a/media/utils/include/mediautils/ServiceUtilities.h b/media/utils/include/mediautils/ServiceUtilities.h
index 2fe2451..de20d55 100644
--- a/media/utils/include/mediautils/ServiceUtilities.h
+++ b/media/utils/include/mediautils/ServiceUtilities.h
@@ -61,6 +61,7 @@
// Used for calls that should come from system server or internal.
// Note: system server is multiprocess for multiple users. audioserver is not.
+// Note: if this method is modified, also update the same method in SensorService.h.
static inline bool isAudioServerOrSystemServerUid(uid_t uid) {
return multiuser_get_app_id(uid) == AID_SYSTEM || uid == AID_AUDIOSERVER;
}
@@ -95,6 +96,7 @@
bool captureMediaOutputAllowed(const AttributionSourceState& attributionSource);
bool captureTunerAudioInputAllowed(const AttributionSourceState& attributionSource);
bool captureVoiceCommunicationOutputAllowed(const AttributionSourceState& attributionSource);
+bool accessUltrasoundAllowed(const AttributionSourceState& attributionSource);
bool captureHotwordAllowed(const AttributionSourceState& attributionSource);
bool settingsAllowed();
bool modifyAudioRoutingAllowed();
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index ec414e0..99f81c7 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -2590,7 +2590,7 @@
{
AudioHwDevice *outHwDev = findSuitableHwDev_l(module, deviceType);
if (outHwDev == NULL) {
- return 0;
+ return nullptr;
}
if (*output == AUDIO_IO_HANDLE_NONE) {
@@ -2599,9 +2599,17 @@
// Audio Policy does not currently request a specific output handle.
// If this is ever needed, see openInput_l() for example code.
ALOGE("openOutput_l requested output handle %d is not AUDIO_IO_HANDLE_NONE", *output);
- return 0;
+ return nullptr;
}
+#ifndef MULTICHANNEL_EFFECT_CHAIN
+ if (flags & AUDIO_OUTPUT_FLAG_SPATIALIZER) {
+ ALOGE("openOutput_l() cannot create spatializer thread "
+ "without #define MULTICHANNEL_EFFECT_CHAIN");
+ return nullptr;
+ }
+#endif
+
mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
// FOR TESTING ONLY:
@@ -2646,18 +2654,11 @@
return thread;
} else {
sp<PlaybackThread> thread;
- //TODO: b/193496180 use spatializer flag at audio HAL when available
- if (flags == (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_FAST
- | AUDIO_OUTPUT_FLAG_DEEP_BUFFER)) {
-#ifdef MULTICHANNEL_EFFECT_CHAIN
+ if (flags & AUDIO_OUTPUT_FLAG_SPATIALIZER) {
thread = new SpatializerThread(this, outputStream, *output,
mSystemReady, mixerConfig);
- ALOGD("openOutput_l() created spatializer output: ID %d thread %p",
+ ALOGV("openOutput_l() created spatializer output: ID %d thread %p",
*output, thread.get());
-#else
- ALOGE("openOutput_l() cannot create spatializer thread "
- "without #define MULTICHANNEL_EFFECT_CHAIN");
-#endif
} else if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
thread = new OffloadThread(this, outputStream, *output, mSystemReady);
ALOGV("openOutput_l() created offload output: ID %d thread %p",
@@ -2683,7 +2684,7 @@
}
}
- return 0;
+ return nullptr;
}
status_t AudioFlinger::openOutput(const media::OpenOutputRequest& request,
@@ -4084,7 +4085,6 @@
// transfer all effects one by one so that new effect chain is created on new thread with
// correct buffer sizes and audio parameters and effect engines reconfigured accordingly
sp<EffectChain> dstChain;
- uint32_t strategy = 0; // prevent compiler warning
sp<EffectModule> effect = chain->getEffectFromId_l(0);
Vector< sp<EffectModule> > removed;
status_t status = NO_ERROR;
@@ -4109,7 +4109,6 @@
status = NO_INIT;
break;
}
- strategy = dstChain->strategy();
}
effect = chain->getEffectFromId_l(0);
}
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index ca7ffdb..b748f9d 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -2413,6 +2413,7 @@
if (i == size - 1 && i != 0) {
mEffects[i - 1]->configure();
mEffects[i - 1]->setOutBuffer(mOutBuffer);
+ mEffects[i - 1]->updateAccessMode(); // reconfig if neeeded.
}
}
mEffects.removeAt(i);
@@ -2422,6 +2423,7 @@
if (i == 0 && size > 1) {
mEffects[0]->configure();
mEffects[0]->setInBuffer(mInBuffer);
+ mEffects[0]->updateAccessMode(); // reconfig if neeeded.
}
ALOGV("removeEffect_l() effect %p, removed from chain %p at rank %zu", effect.get(),
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index 93118b8..45dd258 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -575,6 +575,12 @@
// create a special playback track to render to playback thread.
// this track is given the same buffer as the PatchRecord buffer
+
+ // Default behaviour is to start as soon as possible to have the lowest possible latency even if
+ // it might glitch.
+ // Disable this behavior for FM Tuner source if no fast capture/mixer available.
+ const bool isFmBridge = mAudioPatch.sources[0].ext.device.type == AUDIO_DEVICE_IN_FM_TUNER;
+ const size_t frameCountToBeReady = isFmBridge && !usePassthruPatchRecord ? frameCount / 4 : 1;
sp<PlaybackThread::PatchTrack> tempPatchTrack = new PlaybackThread::PatchTrack(
mPlayback.thread().get(),
streamType,
@@ -584,7 +590,9 @@
frameCount,
tempRecordTrack->buffer(),
tempRecordTrack->bufferSize(),
- outputFlags);
+ outputFlags,
+ {} /*timeout*/,
+ frameCountToBeReady);
status = mPlayback.checkTrack(tempPatchTrack.get());
if (status != NO_ERROR) {
return status;
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 3cce998..aecd4d3 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -193,6 +193,12 @@
}
}
+ static bool checkServerLatencySupported(
+ audio_format_t format, audio_output_flags_t flags) {
+ return audio_is_linear_pcm(format)
+ && (flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC) == 0;
+ }
+
audio_output_flags_t getOutputFlags() const { return mFlags; }
float getSpeed() const { return mSpeed; }
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 43fa781..dd278f0 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -5889,6 +5889,20 @@
return trackCount;
}
+bool AudioFlinger::PlaybackThread::checkRunningTimestamp()
+{
+ uint64_t position = 0;
+ struct timespec unused;
+ const status_t ret = mOutput->getPresentationPosition(&position, &unused);
+ if (ret == NO_ERROR) {
+ if (position != mLastCheckedTimestampPosition) {
+ mLastCheckedTimestampPosition = position;
+ return true;
+ }
+ }
+ return false;
+}
+
// isTrackAllowed_l() must be called with ThreadBase::mLock held
bool AudioFlinger::MixerThread::isTrackAllowed_l(
audio_channel_mask_t channelMask, audio_format_t format,
@@ -6317,19 +6331,24 @@
// fill a buffer, then remove it from active list.
// Only consider last track started for mixer state control
if (--(track->mRetryCount) <= 0) {
- ALOGV("BUFFER TIMEOUT: remove track(%d) from active list", trackId);
- tracksToRemove->add(track);
- // indicate to client process that the track was disabled because of underrun;
- // it will then automatically call start() when data is available
- track->disable();
- // only do hw pause when track is going to be removed due to BUFFER TIMEOUT.
- // unlike mixerthread, HAL can be paused for direct output
- ALOGW("pause because of UNDERRUN, framesReady = %zu,"
- "minFrames = %u, mFormat = %#x",
- framesReady, minFrames, mFormat);
- if (last && mHwSupportsPause && !mHwPaused && !mStandby) {
- doHwPause = true;
- mHwPaused = true;
+ const bool running = checkRunningTimestamp();
+ if (running) { // still running, give us more time.
+ track->mRetryCount = kMaxTrackRetriesOffload;
+ } else {
+ ALOGV("BUFFER TIMEOUT: remove track(%d) from active list", trackId);
+ tracksToRemove->add(track);
+ // indicate to client process that the track was disabled because of
+ // underrun; it will then automatically call start() when data is available
+ track->disable();
+ // only do hw pause when track is going to be removed due to BUFFER TIMEOUT.
+ // unlike mixerthread, HAL can be paused for direct output
+ ALOGW("pause because of UNDERRUN, framesReady = %zu,"
+ "minFrames = %u, mFormat = %#x",
+ framesReady, minFrames, mFormat);
+ if (last && mHwSupportsPause && !mHwPaused && !mStandby) {
+ doHwPause = true;
+ mHwPaused = true;
+ }
}
} else if (last) {
mixerStatus = MIXER_TRACKS_ENABLED;
@@ -6540,6 +6559,7 @@
void AudioFlinger::DirectOutputThread::flushHw_l()
{
+ PlaybackThread::flushHw_l();
mOutput->flush();
mHwPaused = false;
mFlushPending = false;
@@ -6675,8 +6695,7 @@
AudioFlinger::OffloadThread::OffloadThread(const sp<AudioFlinger>& audioFlinger,
AudioStreamOut* output, audio_io_handle_t id, bool systemReady)
: DirectOutputThread(audioFlinger, output, id, OFFLOAD, systemReady),
- mPausedWriteLength(0), mPausedBytesRemaining(0), mKeepWakeLock(true),
- mOffloadUnderrunPosition(~0LL)
+ mPausedWriteLength(0), mPausedBytesRemaining(0), mKeepWakeLock(true)
{
//FIXME: mStandby should be set to true by ThreadBase constructo
mStandby = true;
@@ -6893,19 +6912,7 @@
// No buffers for this track. Give it a few chances to
// fill a buffer, then remove it from active list.
if (--(track->mRetryCount) <= 0) {
- bool running = false;
- uint64_t position = 0;
- struct timespec unused;
- // The running check restarts the retry counter at least once.
- status_t ret = mOutput->stream->getPresentationPosition(&position, &unused);
- if (ret == NO_ERROR && position != mOffloadUnderrunPosition) {
- running = true;
- mOffloadUnderrunPosition = position;
- }
- if (ret == NO_ERROR) {
- ALOGVV("underrun counter, running(%d): %lld vs %lld", running,
- (long long)position, (long long)mOffloadUnderrunPosition);
- }
+ const bool running = checkRunningTimestamp();
if (running) { // still running, give us more time.
track->mRetryCount = kMaxTrackRetriesOffload;
} else {
@@ -6976,7 +6983,6 @@
mPausedBytesRemaining = 0;
// reset bytes written count to reflect that DSP buffers are empty after flush.
mBytesWritten = 0;
- mOffloadUnderrunPosition = ~0LL;
if (mUseAsyncWrite) {
// discard any pending drain or write ack by incrementing sequence
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 43d1055..982893d 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -1376,6 +1376,14 @@
struct audio_patch mDownStreamPatch;
std::atomic_bool mCheckOutputStageEffects{};
+
+ // A differential check on the timestamps to see if there is a change in the
+ // timestamp frame position between the last call to checkRunningTimestamp.
+ uint64_t mLastCheckedTimestampPosition = ~0LL;
+
+ bool checkRunningTimestamp();
+
+ virtual void flushHw_l() { mLastCheckedTimestampPosition = ~0LL; }
};
class MixerThread : public PlaybackThread {
@@ -1493,7 +1501,7 @@
virtual bool checkForNewParameter_l(const String8& keyValuePair,
status_t& status);
- virtual void flushHw_l();
+ void flushHw_l() override;
void setMasterBalance(float balance) override;
@@ -1558,7 +1566,7 @@
OffloadThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
audio_io_handle_t id, bool systemReady);
virtual ~OffloadThread() {};
- virtual void flushHw_l();
+ void flushHw_l() override;
protected:
// threadLoop snippets
@@ -1575,10 +1583,6 @@
size_t mPausedWriteLength; // length in bytes of write interrupted by pause
size_t mPausedBytesRemaining; // bytes still waiting in mixbuffer after resume
bool mKeepWakeLock; // keep wake lock while waiting for write callback
- uint64_t mOffloadUnderrunPosition; // Current frame position for offloaded playback
- // used and valid only during underrun. ~0 if
- // no underrun has occurred during playback and
- // is not reset on standby.
};
class AsyncCallbackThread : public Thread {
@@ -1860,6 +1864,8 @@
bool isTimestampCorrectionEnabled() const override {
// checks popcount for exactly one device.
+ // Is currently disabled. Before enabling,
+ // verify compressed record timestamps.
return audio_is_input_device(mTimestampCorrectedDevice)
&& inDeviceType() == mTimestampCorrectedDevice;
}
diff --git a/services/audioflinger/TrackMetrics.h b/services/audioflinger/TrackMetrics.h
index 7fb69be..30d69ab 100644
--- a/services/audioflinger/TrackMetrics.h
+++ b/services/audioflinger/TrackMetrics.h
@@ -116,6 +116,21 @@
mDeviceStartupMs.add(startupMs);
}
+ void updateMinMaxVolume(int64_t durationNs, double deviceVolume) {
+ if (deviceVolume > mMaxVolume) {
+ mMaxVolume = deviceVolume;
+ mMaxVolumeDurationNs = durationNs;
+ } else if (deviceVolume == mMaxVolume) {
+ mMaxVolumeDurationNs += durationNs;
+ }
+ if (deviceVolume < mMinVolume) {
+ mMinVolume = deviceVolume;
+ mMinVolumeDurationNs = durationNs;
+ } else if (deviceVolume == mMinVolume) {
+ mMinVolumeDurationNs += durationNs;
+ }
+ }
+
// may be called multiple times during an interval
void logVolume(float volume) {
const int64_t timeNs = systemTime();
@@ -123,10 +138,13 @@
if (mStartVolumeTimeNs == 0) {
mDeviceVolume = mVolume = volume;
mLastVolumeChangeTimeNs = mStartVolumeTimeNs = timeNs;
+ updateMinMaxVolume(0, mVolume);
return;
}
+ const int64_t durationNs = timeNs - mLastVolumeChangeTimeNs;
+ updateMinMaxVolume(durationNs, mVolume);
mDeviceVolume = (mDeviceVolume * (mLastVolumeChangeTimeNs - mStartVolumeTimeNs) +
- mVolume * (timeNs - mLastVolumeChangeTimeNs)) / (timeNs - mStartVolumeTimeNs);
+ mVolume * durationNs) / (timeNs - mStartVolumeTimeNs);
mVolume = volume;
mLastVolumeChangeTimeNs = timeNs;
}
@@ -157,7 +175,11 @@
.set(AMEDIAMETRICS_PROP_EVENT, eventName)
.set(AMEDIAMETRICS_PROP_INTERVALCOUNT, (int32_t)mIntervalCount);
if (mIsOut) {
- item.set(AMEDIAMETRICS_PROP_DEVICEVOLUME, mDeviceVolume);
+ item.set(AMEDIAMETRICS_PROP_DEVICEVOLUME, mDeviceVolume)
+ .set(AMEDIAMETRICS_PROP_DEVICEMAXVOLUMEDURATIONNS, mMaxVolumeDurationNs)
+ .set(AMEDIAMETRICS_PROP_DEVICEMAXVOLUME, mMaxVolume)
+ .set(AMEDIAMETRICS_PROP_DEVICEMINVOLUMEDURATIONNS, mMinVolumeDurationNs)
+ .set(AMEDIAMETRICS_PROP_DEVICEMINVOLUME, mMinVolume);
}
if (mDeviceLatencyMs.getN() > 0) {
item.set(AMEDIAMETRICS_PROP_DEVICELATENCYMS, mDeviceLatencyMs.getMean())
@@ -185,6 +207,10 @@
mDeviceVolume = 0.f;
mStartVolumeTimeNs = 0;
mLastVolumeChangeTimeNs = 0;
+ mMinVolume = AMEDIAMETRICS_INITIAL_MIN_VOLUME;
+ mMaxVolume = AMEDIAMETRICS_INITIAL_MAX_VOLUME;
+ mMinVolumeDurationNs = 0;
+ mMaxVolumeDurationNs = 0;
mDeviceLatencyMs.reset();
mDeviceStartupMs.reset();
@@ -214,6 +240,12 @@
int64_t mStartVolumeTimeNs GUARDED_BY(mLock) = 0;
int64_t mLastVolumeChangeTimeNs GUARDED_BY(mLock) = 0;
+ // Min/Max volume
+ double mMinVolume GUARDED_BY(mLock) = AMEDIAMETRICS_INITIAL_MIN_VOLUME;
+ double mMaxVolume GUARDED_BY(mLock) = AMEDIAMETRICS_INITIAL_MAX_VOLUME;
+ int64_t mMinVolumeDurationNs GUARDED_BY(mLock) = 0;
+ int64_t mMaxVolumeDurationNs GUARDED_BY(mLock) = 0;
+
// latency and startup for each interval.
audio_utils::Statistics<double> mDeviceLatencyMs GUARDED_BY(mLock);
audio_utils::Statistics<double> mDeviceStartupMs GUARDED_BY(mLock);
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 616fd78..279ff3d 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -713,8 +713,7 @@
thread->mFastTrackAvailMask &= ~(1 << i);
}
- mServerLatencySupported = thread->type() == ThreadBase::MIXER
- || thread->type() == ThreadBase::DUPLICATING;
+ mServerLatencySupported = checkServerLatencySupported(format, flags);
#ifdef TEE_SINK
mTee.setId(std::string("_") + std::to_string(mThreadIoHandle)
+ "_" + std::to_string(mId) + "_T");
@@ -2636,6 +2635,8 @@
// ALOGD("FrameTime: %lld %lld", (long long)ft.frames, (long long)ft.timeNs);
mKernelFrameTime.store(ft);
if (!audio_is_linear_pcm(mFormat)) {
+ // Stream is direct, return provided timestamp with no conversion
+ mServerProxy->setTimestamp(timestamp);
return;
}
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 33b455f..f6f3b9a 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -392,6 +392,18 @@
* @return NO_ERROR if an output was closed, INVALID_OPERATION or BAD_VALUE otherwise
*/
virtual status_t releaseSpatializerOutput(audio_io_handle_t output) = 0;
+
+ /**
+ * Query how the direct playback is currently supported on the device.
+ * @param attr audio attributes describing the playback use case
+ * @param config audio configuration for the playback
+ * @param directMode out: a set of flags describing how the direct playback is currently
+ * supported on the device
+ * @return NO_ERROR in case of success, DEAD_OBJECT, NO_INIT, BAD_VALUE, PERMISSION_DENIED
+ * in case of error.
+ */
+ virtual audio_direct_mode_t getDirectPlaybackSupport(const audio_attributes_t *attr,
+ const audio_config_t *config) = 0;
};
diff --git a/services/audiopolicy/common/include/Volume.h b/services/audiopolicy/common/include/Volume.h
index 736f8b2..f0636a0 100644
--- a/services/audiopolicy/common/include/Volume.h
+++ b/services/audiopolicy/common/include/Volume.h
@@ -127,6 +127,7 @@
case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
case AUDIO_DEVICE_OUT_USB_HEADSET:
case AUDIO_DEVICE_OUT_BLE_HEADSET:
+ case AUDIO_DEVICE_OUT_BLE_BROADCAST:
return DEVICE_CATEGORY_HEADSET;
case AUDIO_DEVICE_OUT_HEARING_AID:
return DEVICE_CATEGORY_HEARING_AID;
diff --git a/services/audiopolicy/common/include/policy.h b/services/audiopolicy/common/include/policy.h
index 577f641..3d3e0cf 100644
--- a/services/audiopolicy/common/include/policy.h
+++ b/services/audiopolicy/common/include/policy.h
@@ -133,6 +133,7 @@
* - AUDIO_SOURCE_FM_TUNER
* - AUDIO_SOURCE_VOICE_RECOGNITION
* - AUDIO_SOURCE_HOTWORD
+ * - AUDIO_SOURCE_ULTRASOUND
*
* @return the corresponding input source priority or 0 if priority is irrelevant for this source.
* This happens when the specified source cannot share a given input stream (e.g remote submix)
@@ -142,22 +143,24 @@
{
switch (inputSource) {
case AUDIO_SOURCE_VOICE_COMMUNICATION:
- return 9;
+ return 10;
case AUDIO_SOURCE_CAMCORDER:
- return 8;
+ return 9;
case AUDIO_SOURCE_VOICE_PERFORMANCE:
- return 7;
+ return 8;
case AUDIO_SOURCE_UNPROCESSED:
- return 6;
+ return 7;
case AUDIO_SOURCE_MIC:
- return 5;
+ return 6;
case AUDIO_SOURCE_ECHO_REFERENCE:
- return 4;
+ return 5;
case AUDIO_SOURCE_FM_TUNER:
- return 3;
+ return 4;
case AUDIO_SOURCE_VOICE_RECOGNITION:
- return 2;
+ return 3;
case AUDIO_SOURCE_HOTWORD:
+ return 2;
+ case AUDIO_SOURCE_ULTRASOUND:
return 1;
default:
break;
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
index a8fd856..cf1f64c 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
@@ -202,20 +202,6 @@
{AUDIO_FORMAT_AC4, {}}};
}
- //TODO: b/193496180 use spatializer flag at audio HAL when available
- // until then, use DEEP_BUFFER+FAST flag combo to indicate the spatializer output profile
- void convertSpatializerFlag()
- {
- for (const auto& hwModule : mHwModules) {
- for (const auto& curProfile : hwModule->getOutputProfiles()) {
- if (curProfile->getFlags()
- == (AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_DEEP_BUFFER)) {
- curProfile->setFlags(AUDIO_OUTPUT_FLAG_SPATIALIZER);
- }
- }
- }
- }
-
private:
static const constexpr char* const kDefaultEngineLibraryNameSuffix = "default";
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 235e4aa..663c80a 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -565,10 +565,11 @@
mFlags = (audio_output_flags_t)(mFlags | flags);
- //TODO: b/193496180 use spatializer flag at audio HAL when available
- audio_output_flags_t halFlags = mFlags;
- if ((mFlags & AUDIO_OUTPUT_FLAG_SPATIALIZER) != 0) {
- halFlags = (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_DEEP_BUFFER);
+ // If no mixer config is specified for a spatializer output, default to 5.1 for proper
+ // configuration of the final downmixer or spatializer
+ if ((mFlags & AUDIO_OUTPUT_FLAG_SPATIALIZER) != 0
+ && mixerConfig == nullptr) {
+ lMixerConfig.channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
}
ALOGV("opening output for device %s profile %p name %s",
@@ -580,7 +581,7 @@
&lMixerConfig,
device,
&mLatency,
- halFlags);
+ mFlags);
if (status == NO_ERROR) {
LOG_ALWAYS_FATAL_IF(*output == AUDIO_IO_HANDLE_NONE,
diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
index 4dfef73..69cad9b 100644
--- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
@@ -483,7 +483,14 @@
if (!flags.empty()) {
// Source role
if (portRole == AUDIO_PORT_ROLE_SOURCE) {
- mixPort->setFlags(OutputFlagConverter::maskFromString(flags, mFlagsSeparator.c_str()));
+ //TODO: b/193496180 use spatializer flag at audio HAL when available until then,
+ // use DEEP_BUFFER+FAST flag combo to indicate the spatializer output profile
+ uint32_t intFlags =
+ OutputFlagConverter::maskFromString(flags, mFlagsSeparator.c_str());
+ if (intFlags == (AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_DEEP_BUFFER)) {
+ intFlags = AUDIO_OUTPUT_FLAG_SPATIALIZER;
+ }
+ mixPort->setFlags(intFlags);
} else {
// Sink role
mixPort->setFlags(InputFlagConverter::maskFromString(flags, mFlagsSeparator.c_str()));
diff --git a/services/audiopolicy/engine/common/src/EngineDefaultConfig.h b/services/audiopolicy/engine/common/src/EngineDefaultConfig.h
index 665c2dd..b036e12 100644
--- a/services/audiopolicy/engine/common/src/EngineDefaultConfig.h
+++ b/services/audiopolicy/engine/common/src/EngineDefaultConfig.h
@@ -122,8 +122,12 @@
{"STRATEGY_TRANSMITTED_THROUGH_SPEAKER",
{
{"", AUDIO_STREAM_TTS, "AUDIO_STREAM_TTS",
- {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT,
- AUDIO_FLAG_BEACON, ""}}
+ {
+ {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT,
+ AUDIO_FLAG_BEACON, ""},
+ {AUDIO_CONTENT_TYPE_ULTRASOUND, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT,
+ AUDIO_FLAG_NONE, ""}
+ }
}
},
}
diff --git a/services/audiopolicy/engine/common/src/LastRemovableMediaDevices.cpp b/services/audiopolicy/engine/common/src/LastRemovableMediaDevices.cpp
index b3f8947..06cc799 100644
--- a/services/audiopolicy/engine/common/src/LastRemovableMediaDevices.cpp
+++ b/services/audiopolicy/engine/common/src/LastRemovableMediaDevices.cpp
@@ -85,6 +85,7 @@
case AUDIO_DEVICE_OUT_HEARING_AID:
case AUDIO_DEVICE_OUT_BLE_HEADSET:
case AUDIO_DEVICE_OUT_BLE_SPEAKER:
+ case AUDIO_DEVICE_OUT_BLE_BROADCAST:
return GROUP_BT_A2DP;
default:
return GROUP_NONE;
diff --git a/services/audiopolicy/engine/config/include/EngineConfig.h b/services/audiopolicy/engine/config/include/EngineConfig.h
index c565926..2ebb7df 100644
--- a/services/audiopolicy/engine/config/include/EngineConfig.h
+++ b/services/audiopolicy/engine/config/include/EngineConfig.h
@@ -70,7 +70,7 @@
using ProductStrategies = std::vector<ProductStrategy>;
-using ValuePair = std::pair<uint32_t, std::string>;
+using ValuePair = std::tuple<uint64_t, uint32_t, std::string>;
using ValuePairs = std::vector<ValuePair>;
struct CriterionType
diff --git a/services/audiopolicy/engine/config/src/EngineConfig.cpp b/services/audiopolicy/engine/config/src/EngineConfig.cpp
index 81e803f..6f560d5 100644
--- a/services/audiopolicy/engine/config/src/EngineConfig.cpp
+++ b/services/audiopolicy/engine/config/src/EngineConfig.cpp
@@ -80,6 +80,7 @@
struct Attributes {
static constexpr const char *literal = "literal";
static constexpr const char *numerical = "numerical";
+ static constexpr const char *androidType = "android_type";
};
static android::status_t deserialize(_xmlDoc *doc, const _xmlNode *root,
@@ -349,7 +350,16 @@
ALOGE("%s: No attribute %s found", __FUNCTION__, Attributes::literal);
return BAD_VALUE;
}
- uint32_t numerical = 0;
+ uint32_t androidType = 0;
+ std::string androidTypeliteral = getXmlAttribute(child, Attributes::androidType);
+ if (!androidTypeliteral.empty()) {
+ ALOGV("%s: androidType %s", __FUNCTION__, androidTypeliteral.c_str());
+ if (!convertTo(androidTypeliteral, androidType)) {
+ ALOGE("%s: : Invalid typeset value(%s)", __FUNCTION__, androidTypeliteral.c_str());
+ return BAD_VALUE;
+ }
+ }
+ uint64_t numerical = 0;
std::string numericalTag = getXmlAttribute(child, Attributes::numerical);
if (numericalTag.empty()) {
ALOGE("%s: No attribute %s found", __FUNCTION__, Attributes::literal);
@@ -359,7 +369,7 @@
ALOGE("%s: : Invalid value(%s)", __FUNCTION__, numericalTag.c_str());
return BAD_VALUE;
}
- values.push_back({numerical, literal});
+ values.push_back({numerical, androidType, literal});
return NO_ERROR;
}
diff --git a/services/audiopolicy/engineconfigurable/interface/AudioPolicyPluginInterface.h b/services/audiopolicy/engineconfigurable/interface/AudioPolicyPluginInterface.h
index 1fc2264..9fd8b8e 100644
--- a/services/audiopolicy/engineconfigurable/interface/AudioPolicyPluginInterface.h
+++ b/services/audiopolicy/engineconfigurable/interface/AudioPolicyPluginInterface.h
@@ -77,12 +77,12 @@
* Set the input device to be used by an input source.
*
* @param[in] inputSource: name of the input source for which the device to use has to be set
- * @param[in] devices; mask of devices to be used for the given input source.
+ * @param[in] devices: mask of devices to be used for the given input source.
*
* @return true if the devices were set correclty for this input source, false otherwise.
*/
virtual bool setDeviceForInputSource(const audio_source_t &inputSource,
- audio_devices_t device) = 0;
+ uint64_t device) = 0;
virtual void setDeviceAddressForProductStrategy(product_strategy_t strategy,
const std::string &address) = 0;
@@ -91,12 +91,12 @@
* Set the device to be used by a product strategy.
*
* @param[in] strategy: name of the product strategy for which the device to use has to be set
- * @param[in] devices; mask of devices to be used for the given strategy.
+ * @param[in] devices: mask of devices to be used for the given strategy.
*
* @return true if the devices were set correclty for this strategy, false otherwise.
*/
virtual bool setDeviceTypesForProductStrategy(product_strategy_t strategy,
- audio_devices_t devices) = 0;
+ uint64_t devices) = 0;
virtual product_strategy_t getProductStrategyByName(const std::string &address) = 0;
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem-CommonTypes.xml.in b/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem-CommonTypes.xml.in
index 2e9f37e..2c4c7b5 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem-CommonTypes.xml.in
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem-CommonTypes.xml.in
@@ -10,8 +10,8 @@
<!--#################### GLOBAL COMPONENTS END ####################-->
<!-- Automatically filled from audio-base.h file -->
- <ComponentType Name="OutputDevicesMask" Description="32th bit is not allowed as dedicated for input devices detection">
- <BitParameterBlock Name="mask" Size="32">
+ <ComponentType Name="OutputDevicesMask" Description="64bit representation of devices">
+ <BitParameterBlock Name="mask" Size="64">
</BitParameterBlock>
</ComponentType>
@@ -19,8 +19,8 @@
profile. It must match with the Input device enum parameter.
-->
<!-- Automatically filled from audio-base.h file -->
- <ComponentType Name="InputDevicesMask">
- <BitParameterBlock Name="mask" Size="32">
+ <ComponentType Name="InputDevicesMask" Description="64bit representation of devices">
+ <BitParameterBlock Name="mask" Size="64">
</BitParameterBlock>
</ComponentType>
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.cpp b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.cpp
index f8a6fc0..df4e3e9 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.cpp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.cpp
@@ -45,7 +45,7 @@
bool InputSource::sendToHW(string & /*error*/)
{
- audio_devices_t applicableInputDevice;
+ uint64_t applicableInputDevice;
blackboardRead(&applicableInputDevice, sizeof(applicableInputDevice));
return mPolicyPluginInterface->setDeviceForInputSource(mId, applicableInputDevice);
}
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/ProductStrategy.h b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/ProductStrategy.h
index 6c8eb65..e65946e 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/ProductStrategy.h
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/ProductStrategy.h
@@ -32,7 +32,7 @@
struct Device
{
- audio_devices_t applicableDevice; /**< applicable device for this strategy. */
+ uint64_t applicableDevice; /**< applicable device for this strategy. */
char deviceAddress[mMaxStringSize]; /**< device address associated with this strategy. */
} __attribute__((packed));
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.cpp b/services/audiopolicy/engineconfigurable/src/Engine.cpp
index b0c376a..3d74920 100644
--- a/services/audiopolicy/engineconfigurable/src/Engine.cpp
+++ b/services/audiopolicy/engineconfigurable/src/Engine.cpp
@@ -36,6 +36,8 @@
#include <media/TypeConverter.h>
+#include <cinttypes>
+
using std::string;
using std::map;
@@ -166,16 +168,13 @@
status_t Engine::setDeviceConnectionState(const sp<DeviceDescriptor> device,
audio_policy_dev_state_t state)
{
- mPolicyParameterMgr->setDeviceConnectionState(
- device->type(), device->address().c_str(), state);
+ mPolicyParameterMgr->setDeviceConnectionState(device->type(), device->address(), state);
if (audio_is_output_device(device->type())) {
- // FIXME: Use DeviceTypeSet when the interface is ready
return mPolicyParameterMgr->setAvailableOutputDevices(
- deviceTypesToBitMask(getApmObserver()->getAvailableOutputDevices().types()));
+ getApmObserver()->getAvailableOutputDevices().types());
} else if (audio_is_input_device(device->type())) {
- // FIXME: Use DeviceTypeSet when the interface is ready
return mPolicyParameterMgr->setAvailableInputDevices(
- deviceTypesToBitMask(getApmObserver()->getAvailableInputDevices().types()));
+ getApmObserver()->getAvailableInputDevices().types());
}
return EngineBase::setDeviceConnectionState(device, state);
}
@@ -299,8 +298,13 @@
if (device != nullptr) {
return DeviceVector(device);
}
+ return fromCache? getCachedDevices(strategy) : getDevicesForProductStrategy(strategy);
+}
- return fromCache? mDevicesForStrategies.at(strategy) : getDevicesForProductStrategy(strategy);
+DeviceVector Engine::getCachedDevices(product_strategy_t ps) const
+{
+ return mDevicesForStrategies.find(ps) != mDevicesForStrategies.end() ?
+ mDevicesForStrategies.at(ps) : DeviceVector{};
}
DeviceVector Engine::getOutputDevicesForStream(audio_stream_type_t stream, bool fromCache) const
@@ -369,17 +373,28 @@
getProductStrategies().at(strategy)->setDeviceAddress(address);
}
-bool Engine::setDeviceTypesForProductStrategy(product_strategy_t strategy, audio_devices_t devices)
+bool Engine::setDeviceTypesForProductStrategy(product_strategy_t strategy, uint64_t devices)
{
if (getProductStrategies().find(strategy) == getProductStrategies().end()) {
- ALOGE("%s: set device %d on invalid strategy %d", __FUNCTION__, devices, strategy);
+ ALOGE("%s: set device %" PRId64 " on invalid strategy %d", __FUNCTION__, devices, strategy);
return false;
}
- // FIXME: stop using deviceTypesFromBitMask when the interface is ready
- getProductStrategies().at(strategy)->setDeviceTypes(deviceTypesFromBitMask(devices));
+ // Here device matches the criterion value, need to rebuitd android device types;
+ DeviceTypeSet types =
+ mPolicyParameterMgr->convertDeviceCriterionValueToDeviceTypes(devices, true /*isOut*/);
+ getProductStrategies().at(strategy)->setDeviceTypes(types);
return true;
}
+bool Engine::setDeviceForInputSource(const audio_source_t &inputSource, uint64_t device)
+{
+ DeviceTypeSet types = mPolicyParameterMgr->convertDeviceCriterionValueToDeviceTypes(
+ device, false /*isOut*/);
+ ALOG_ASSERT(types.size() <= 1, "one input device expected at most");
+ audio_devices_t deviceType = types.empty() ? AUDIO_DEVICE_IN_DEFAULT : *types.begin();
+ return setPropertyForKey<audio_devices_t, audio_source_t>(deviceType, inputSource);
+}
+
template <>
EngineInterface *Engine::queryInterface()
{
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.h b/services/audiopolicy/engineconfigurable/src/Engine.h
index d8e2742..4b559f0 100644
--- a/services/audiopolicy/engineconfigurable/src/Engine.h
+++ b/services/audiopolicy/engineconfigurable/src/Engine.h
@@ -82,15 +82,12 @@
bool setVolumeProfileForStream(const audio_stream_type_t &stream,
const audio_stream_type_t &volumeProfile) override;
- bool setDeviceForInputSource(const audio_source_t &inputSource, audio_devices_t device) override
- {
- return setPropertyForKey<audio_devices_t, audio_source_t>(device, inputSource);
- }
+ bool setDeviceForInputSource(const audio_source_t &inputSource, uint64_t device) override;
+
void setDeviceAddressForProductStrategy(product_strategy_t strategy,
const std::string &address) override;
- bool setDeviceTypesForProductStrategy(product_strategy_t strategy,
- audio_devices_t devices) override;
+ bool setDeviceTypesForProductStrategy(product_strategy_t strategy, uint64_t devices) override;
product_strategy_t getProductStrategyByName(const std::string &name) override
{
@@ -126,6 +123,7 @@
status_t loadAudioPolicyEngineConfig();
DeviceVector getDevicesForProductStrategy(product_strategy_t strategy) const;
+ DeviceVector getCachedDevices(product_strategy_t ps) const;
/**
* Policy Parameter Manager hidden through a wrapper.
diff --git a/services/audiopolicy/engineconfigurable/src/InputSource.cpp b/services/audiopolicy/engineconfigurable/src/InputSource.cpp
index f4645e6..6fd2b70 100644
--- a/services/audiopolicy/engineconfigurable/src/InputSource.cpp
+++ b/services/audiopolicy/engineconfigurable/src/InputSource.cpp
@@ -26,7 +26,8 @@
status_t Element<audio_source_t>::setIdentifier(audio_source_t identifier)
{
if (identifier > AUDIO_SOURCE_MAX && identifier != AUDIO_SOURCE_HOTWORD
- && identifier != AUDIO_SOURCE_FM_TUNER && identifier != AUDIO_SOURCE_ECHO_REFERENCE) {
+ && identifier != AUDIO_SOURCE_FM_TUNER && identifier != AUDIO_SOURCE_ECHO_REFERENCE
+ && identifier != AUDIO_SOURCE_ULTRASOUND) {
return BAD_VALUE;
}
mIdentifier = identifier;
@@ -46,12 +47,6 @@
template <>
status_t Element<audio_source_t>::set(audio_devices_t devices)
{
- if (devices == AUDIO_DEVICE_NONE) {
- // Reset
- mApplicableDevices = devices;
- return NO_ERROR;
- }
- devices = static_cast<audio_devices_t>(devices | AUDIO_DEVICE_BIT_IN);
if (!audio_is_input_device(devices)) {
ALOGE("%s: trying to set an invalid device 0x%X for input source %s",
__FUNCTION__, devices, getName().c_str());
diff --git a/services/audiopolicy/engineconfigurable/tools/buildCommonTypesStructureFile.py b/services/audiopolicy/engineconfigurable/tools/buildCommonTypesStructureFile.py
index 43b3dd2..86ac76f 100755
--- a/services/audiopolicy/engineconfigurable/tools/buildCommonTypesStructureFile.py
+++ b/services/audiopolicy/engineconfigurable/tools/buildCommonTypesStructureFile.py
@@ -55,7 +55,7 @@
while i < decimal:
i = i << 1
pos = pos + 1
- if pos == 32:
+ if pos == 64:
return -1
# TODO: b/168065706. This is just to fix the build. That the problem of devices with
@@ -132,6 +132,9 @@
logging.info("Checking Android Header file {}".format(androidaudiobaseheaderFile))
+ multi_bit_output_device_shift = 32
+ multi_bit_input_device_shift = 32
+
for line_number, line in enumerate(androidaudiobaseheaderFile):
match = criteria_pattern.match(line)
if match:
@@ -143,16 +146,36 @@
component_type_numerical_value = match.groupdict()['values']
- # for AUDIO_DEVICE_IN: need to remove sign bit / rename default to stub
+ # for AUDIO_DEVICE_IN: rename default to stub
if component_type_name == "InputDevicesMask":
- component_type_numerical_value = str(int(component_type_numerical_value, 0) & ~2147483648)
+ component_type_numerical_value = str(int(component_type_numerical_value, 0))
if component_type_literal == "default":
component_type_literal = "stub"
+ string_int = int(component_type_numerical_value, 0)
+ num_bits = bin(string_int).count("1")
+ if num_bits > 1:
+ logging.info("The value {} is for criterion {} binary rep {} has {} bits sets"
+ .format(component_type_numerical_value, component_type_name, bin(string_int), num_bits))
+ string_int = 2**multi_bit_input_device_shift
+ logging.info("new val assigned is {} {}" .format(string_int, bin(string_int)))
+ multi_bit_input_device_shift += 1
+ component_type_numerical_value = str(string_int)
+
if component_type_name == "OutputDevicesMask":
if component_type_literal == "default":
component_type_literal = "stub"
+ string_int = int(component_type_numerical_value, 0)
+ num_bits = bin(string_int).count("1")
+ if num_bits > 1:
+ logging.info("The value {} is for criterion {} binary rep {} has {} bits sets"
+ .format(component_type_numerical_value, component_type_name, bin(string_int), num_bits))
+ string_int = 2**multi_bit_output_device_shift
+ logging.info("new val assigned is {} {}" .format(string_int, bin(string_int)))
+ multi_bit_output_device_shift += 1
+ component_type_numerical_value = str(string_int)
+
# Remove duplicated numerical values
if int(component_type_numerical_value, 0) in all_component_types[component_type_name].values():
logging.info("The value {}:{} is duplicated for criterion {}, KEEPING LATEST".format(component_type_numerical_value, component_type_literal, component_type_name))
diff --git a/services/audiopolicy/engineconfigurable/tools/buildPolicyCriterionTypes.py b/services/audiopolicy/engineconfigurable/tools/buildPolicyCriterionTypes.py
index 76c35c1..a15a6ba 100755
--- a/services/audiopolicy/engineconfigurable/tools/buildPolicyCriterionTypes.py
+++ b/services/audiopolicy/engineconfigurable/tools/buildPolicyCriterionTypes.py
@@ -85,6 +85,9 @@
return argparser.parse_args()
+output_devices_type_value = {}
+input_devices_type_value = {}
+
def generateXmlCriterionTypesFile(criterionTypes, addressCriteria, criterionTypesFile, outputFile):
logging.info("Importing criterionTypesFile {}".format(criterionTypesFile))
@@ -102,6 +105,11 @@
value_node.set('numerical', str(value))
value_node.set('literal', key)
+ if criterion_type.get('name') == "OutputDevicesMaskType":
+ value_node.set('android_type', output_devices_type_value[key])
+ if criterion_type.get('name') == "InputDevicesMaskType":
+ value_node.set('android_type', input_devices_type_value[key])
+
if addressCriteria:
for criterion_name, values_list in addressCriteria.items():
for criterion_type in criterion_types_root.findall('criterion_type'):
@@ -200,10 +208,8 @@
#
ignored_values = ['CNT', 'MAX', 'ALL', 'NONE']
- #
- # Reaching 32 bit limit for inclusive criterion out devices: removing
- #
- ignored_output_device_values = ['BleSpeaker', 'BleHeadset']
+ multi_bit_outputdevice_shift = 32
+ multi_bit_inputdevice_shift = 32
criteria_pattern = re.compile(
r"\s*V\((?P<type>(?:"+'|'.join(criterion_mapping_table.keys()) + "))_" \
@@ -223,28 +229,59 @@
''.join((w.capitalize() for w in match.groupdict()['literal'].split('_')))
criterion_numerical_value = match.groupdict()['values']
- # for AUDIO_DEVICE_IN: need to remove sign bit / rename default to stub
+ # for AUDIO_DEVICE_IN: rename default to stub
if criterion_name == "InputDevicesMaskType":
if criterion_literal == "Default":
criterion_numerical_value = str(int("0x40000000", 0))
+ input_devices_type_value[criterion_literal] = "0xC0000000"
else:
try:
string_int = int(criterion_numerical_value, 0)
+ # Append AUDIO_DEVICE_IN for android type tag
+ input_devices_type_value[criterion_literal] = hex(string_int | 2147483648)
+
+ num_bits = bin(string_int).count("1")
+ if num_bits > 1:
+ logging.info("The value {}:{} is for criterion {} binary rep {} has {} bits sets"
+ .format(criterion_numerical_value, criterion_literal, criterion_name, bin(string_int), num_bits))
+ string_int = 2**multi_bit_inputdevice_shift
+ logging.info("new val assigned is {} {}" .format(string_int, bin(string_int)))
+ multi_bit_inputdevice_shift += 1
+ criterion_numerical_value = str(string_int)
+
except ValueError:
# Handle the exception
logging.info("value {}:{} for criterion {} is not a number, ignoring"
.format(criterion_numerical_value, criterion_literal, criterion_name))
continue
- criterion_numerical_value = str(int(criterion_numerical_value, 0) & ~2147483648)
if criterion_name == "OutputDevicesMaskType":
if criterion_literal == "Default":
criterion_numerical_value = str(int("0x40000000", 0))
- if criterion_literal in ignored_output_device_values:
- logging.info("OutputDevicesMaskType skipping {}".format(criterion_literal))
- continue
+ output_devices_type_value[criterion_literal] = "0x40000000"
+ else:
+ try:
+ string_int = int(criterion_numerical_value, 0)
+ output_devices_type_value[criterion_literal] = criterion_numerical_value
+
+ num_bits = bin(string_int).count("1")
+ if num_bits > 1:
+ logging.info("The value {}:{} is for criterion {} binary rep {} has {} bits sets"
+ .format(criterion_numerical_value, criterion_literal, criterion_name, bin(string_int), num_bits))
+ string_int = 2**multi_bit_outputdevice_shift
+ logging.info("new val assigned is {} {}" .format(string_int, bin(string_int)))
+ multi_bit_outputdevice_shift += 1
+ criterion_numerical_value = str(string_int)
+
+ except ValueError:
+ # Handle the exception
+ logging.info("The value {}:{} is for criterion {} is not a number, ignoring"
+ .format(criterion_numerical_value, criterion_literal, criterion_name))
+ continue
+
try:
string_int = int(criterion_numerical_value, 0)
+
except ValueError:
# Handle the exception
logging.info("The value {}:{} is for criterion {} is not a number, ignoring"
diff --git a/services/audiopolicy/engineconfigurable/wrapper/Android.bp b/services/audiopolicy/engineconfigurable/wrapper/Android.bp
index 3e04b68..0ef0b82 100644
--- a/services/audiopolicy/engineconfigurable/wrapper/Android.bp
+++ b/services/audiopolicy/engineconfigurable/wrapper/Android.bp
@@ -19,6 +19,7 @@
header_libs: [
"libbase_headers",
"libaudiopolicycommon",
+ "libaudiofoundation_headers",
],
shared_libs: [
"liblog",
diff --git a/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp b/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
index 63990ac..099d55d 100644
--- a/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
+++ b/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
@@ -23,6 +23,7 @@
#include <SelectionCriterionInterface.h>
#include <media/convert.h>
#include <algorithm>
+#include <cutils/bitops.h>
#include <cutils/config_utils.h>
#include <cutils/misc.h>
#include <fstream>
@@ -31,6 +32,7 @@
#include <string>
#include <vector>
#include <stdint.h>
+#include <cinttypes>
#include <cmath>
#include <utils/Log.h>
@@ -124,9 +126,22 @@
for (auto pair : pairs) {
std::string error;
- ALOGV("%s: Adding pair %d,%s for criterionType %s", __FUNCTION__, pair.first,
- pair.second.c_str(), name.c_str());
- criterionType->addValuePair(pair.first, pair.second, error);
+ ALOGV("%s: Adding pair %" PRIu64", %s for criterionType %s", __func__, std::get<0>(pair),
+ std::get<2>(pair).c_str(), name.c_str());
+ criterionType->addValuePair(std::get<0>(pair), std::get<2>(pair), error);
+
+ if (name == gOutputDeviceCriterionName) {
+ ALOGV("%s: Adding mOutputDeviceToCriterionTypeMap %d %" PRIu64" for criterionType %s",
+ __func__, std::get<1>(pair), std::get<0>(pair), name.c_str());
+ audio_devices_t androidType = static_cast<audio_devices_t>(std::get<1>(pair));
+ mOutputDeviceToCriterionTypeMap[androidType] = std::get<0>(pair);
+ }
+ if (name == gInputDeviceCriterionName) {
+ ALOGV("%s: Adding mInputDeviceToCriterionTypeMap %d %" PRIu64" for criterionType %s",
+ __func__, std::get<1>(pair), std::get<0>(pair), name.c_str());
+ audio_devices_t androidType = static_cast<audio_devices_t>(std::get<1>(pair));
+ mInputDeviceToCriterionTypeMap[androidType] = std::get<0>(pair);
+ }
}
ALOG_ASSERT(mPolicyCriteria.find(name) == mPolicyCriteria.end(),
"%s: Criterion %s already added", __FUNCTION__, name.c_str());
@@ -135,7 +150,7 @@
mPolicyCriteria[name] = criterion;
if (not defaultValue.empty()) {
- int numericalValue = 0;
+ uint64_t numericalValue = 0;
if (not criterionType->getNumericalValue(defaultValue.c_str(), numericalValue)) {
ALOGE("%s; trying to apply invalid default literal value (%s)", __FUNCTION__,
defaultValue.c_str());
@@ -263,7 +278,7 @@
}
status_t ParameterManagerWrapper::setDeviceConnectionState(
- audio_devices_t type, const std::string address, audio_policy_dev_state_t state)
+ audio_devices_t type, const std::string &address, audio_policy_dev_state_t state)
{
std::string criterionName = audio_is_output_device(type) ?
gOutputDeviceAddressCriterionName : gInputDeviceAddressCriterionName;
@@ -279,7 +294,7 @@
}
auto criterionType = criterion->getCriterionType();
- int deviceAddressId;
+ uint64_t deviceAddressId;
if (not criterionType->getNumericalValue(address.c_str(), deviceAddressId)) {
ALOGW("%s: unknown device address reported (%s) for criterion %s", __FUNCTION__,
address.c_str(), criterionName.c_str());
@@ -296,28 +311,28 @@
return NO_ERROR;
}
-status_t ParameterManagerWrapper::setAvailableInputDevices(audio_devices_t inputDevices)
+status_t ParameterManagerWrapper::setAvailableInputDevices(const DeviceTypeSet &types)
{
ISelectionCriterionInterface *criterion =
getElement<ISelectionCriterionInterface>(gInputDeviceCriterionName, mPolicyCriteria);
if (criterion == NULL) {
- ALOGE("%s: no criterion found for %s", __FUNCTION__, gInputDeviceCriterionName);
+ ALOGE("%s: no criterion found for %s", __func__, gInputDeviceCriterionName);
return DEAD_OBJECT;
}
- criterion->setCriterionState(inputDevices & ~AUDIO_DEVICE_BIT_IN);
+ criterion->setCriterionState(convertDeviceTypesToCriterionValue(types));
applyPlatformConfiguration();
return NO_ERROR;
}
-status_t ParameterManagerWrapper::setAvailableOutputDevices(audio_devices_t outputDevices)
+status_t ParameterManagerWrapper::setAvailableOutputDevices(const DeviceTypeSet &types)
{
ISelectionCriterionInterface *criterion =
getElement<ISelectionCriterionInterface>(gOutputDeviceCriterionName, mPolicyCriteria);
if (criterion == NULL) {
- ALOGE("%s: no criterion found for %s", __FUNCTION__, gOutputDeviceCriterionName);
+ ALOGE("%s: no criterion found for %s", __func__, gOutputDeviceCriterionName);
return DEAD_OBJECT;
}
- criterion->setCriterionState(outputDevices);
+ criterion->setCriterionState(convertDeviceTypesToCriterionValue(types));
applyPlatformConfiguration();
return NO_ERROR;
}
@@ -327,5 +342,45 @@
mPfwConnector->applyConfigurations();
}
+uint64_t ParameterManagerWrapper::convertDeviceTypeToCriterionValue(audio_devices_t type) const {
+ bool isOut = audio_is_output_devices(type);
+ uint32_t typeMask = isOut ? type : (type & ~AUDIO_DEVICE_BIT_IN);
+
+ const auto &adapters = isOut ? mOutputDeviceToCriterionTypeMap : mInputDeviceToCriterionTypeMap;
+ // Only multibit devices need adaptation.
+ if (popcount(typeMask) > 1) {
+ const auto &adapter = adapters.find(type);
+ if (adapter != adapters.end()) {
+ ALOGV("%s: multibit device %d converted to criterion %" PRIu64, __func__, type,
+ adapter->second);
+ return adapter->second;
+ }
+ ALOGE("%s: failed to find map for multibit device %d", __func__, type);
+ return 0;
+ }
+ return typeMask;
+}
+
+uint64_t ParameterManagerWrapper::convertDeviceTypesToCriterionValue(
+ const DeviceTypeSet &types) const {
+ uint64_t criterionValue = 0;
+ for (const auto &type : types) {
+ criterionValue += convertDeviceTypeToCriterionValue(type);
+ }
+ return criterionValue;
+}
+
+DeviceTypeSet ParameterManagerWrapper::convertDeviceCriterionValueToDeviceTypes(
+ uint64_t criterionValue, bool isOut) const {
+ DeviceTypeSet deviceTypes;
+ const auto &adapters = isOut ? mOutputDeviceToCriterionTypeMap : mInputDeviceToCriterionTypeMap;
+ for (const auto &adapter : adapters) {
+ if ((adapter.second & criterionValue) == adapter.second) {
+ deviceTypes.insert(adapter.first);
+ }
+ }
+ return deviceTypes;
+}
+
} // namespace audio_policy
} // namespace android
diff --git a/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h b/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h
index 62b129a..fa4ae1e 100644
--- a/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h
+++ b/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h
@@ -16,6 +16,7 @@
#pragma once
+#include <media/AudioContainers.h>
#include <system/audio.h>
#include <system/audio_policy.h>
#include <utils/Errors.h>
@@ -35,7 +36,8 @@
namespace android {
namespace audio_policy {
-using ValuePair = std::pair<uint32_t, std::string>;
+using ValuePair = std::tuple<uint64_t, uint32_t, std::string>;
+using DeviceToCriterionTypeAdapter = std::map<audio_devices_t, uint64_t>;
using ValuePairs = std::vector<ValuePair>;
class ParameterManagerWrapper
@@ -105,7 +107,7 @@
*
* @return NO_ERROR if devices criterion updated correctly, error code otherwise.
*/
- status_t setAvailableInputDevices(audio_devices_t inputDevices);
+ status_t setAvailableInputDevices(const DeviceTypeSet &inputDeviceTypes);
/**
* Set the available output devices i.e. set the associated policy parameter framework criterion
@@ -114,7 +116,7 @@
*
* @return NO_ERROR if devices criterion updated correctly, error code otherwise.
*/
- status_t setAvailableOutputDevices(audio_devices_t outputDevices);
+ status_t setAvailableOutputDevices(const DeviceTypeSet &outputDeviceTypes);
/**
* @brief setDeviceConnectionState propagates a state event on a given device(s)
@@ -124,7 +126,7 @@
* @return NO_ERROR if new state corretly propagated to Engine Parameter-Framework, error
* code otherwise.
*/
- status_t setDeviceConnectionState(audio_devices_t type, const std::string address,
+ status_t setDeviceConnectionState(audio_devices_t type, const std::string &address,
audio_policy_dev_state_t state);
/**
@@ -138,6 +140,13 @@
status_t addCriterion(const std::string &name, bool isInclusive, ValuePairs pairs,
const std::string &defaultValue);
+ uint64_t convertDeviceTypeToCriterionValue(audio_devices_t type) const;
+
+ uint64_t convertDeviceTypesToCriterionValue(const DeviceTypeSet &types) const;
+
+ DeviceTypeSet convertDeviceCriterionValueToDeviceTypes(
+ uint64_t criterionValue, bool isOut) const;
+
private:
/**
* Apply the configuration of the platform on the policy parameter manager.
@@ -211,6 +220,9 @@
template <typename T>
struct parameterManagerElementSupported;
+ DeviceToCriterionTypeAdapter mOutputDeviceToCriterionTypeMap;
+ DeviceToCriterionTypeAdapter mInputDeviceToCriterionTypeMap;
+
static const char *const mPolicyPfwDefaultConfFileName; /**< Default Policy PFW top file name.*/
static const char *const mPolicyPfwVendorConfFileName; /**< Vendor Policy PFW top file name.*/
};
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index c73c17d..4c3d92c 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -460,6 +460,7 @@
case AUDIO_SOURCE_HOTWORD:
case AUDIO_SOURCE_CAMCORDER:
case AUDIO_SOURCE_VOICE_PERFORMANCE:
+ case AUDIO_SOURCE_ULTRASOUND:
inputSource = AUDIO_SOURCE_VOICE_COMMUNICATION;
break;
default:
@@ -586,6 +587,10 @@
device = availableDevices.getDevice(
AUDIO_DEVICE_IN_ECHO_REFERENCE, String8(""), AUDIO_FORMAT_DEFAULT);
break;
+ case AUDIO_SOURCE_ULTRASOUND:
+ device = availableDevices.getFirstExistingDevice({
+ AUDIO_DEVICE_IN_BUILTIN_MIC, AUDIO_DEVICE_IN_BACK_MIC});
+ break;
default:
ALOGW("getDeviceForInputSource() invalid input source %d", inputSource);
break;
@@ -645,7 +650,7 @@
// there is a preferred device, is it available?
preferredAvailableDevVec =
availableOutputDevices.getDevicesFromDeviceTypeAddrVec(preferredStrategyDevices);
- if (preferredAvailableDevVec.size() == preferredAvailableDevVec.size()) {
+ if (preferredAvailableDevVec.size() == preferredStrategyDevices.size()) {
ALOGVV("%s using pref device %s for strategy %u",
__func__, preferredAvailableDevVec.toString().c_str(), strategy);
return preferredAvailableDevVec;
diff --git a/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp b/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
index 8584702..654e4bf 100644
--- a/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
+++ b/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
@@ -841,6 +841,8 @@
: AudioPolicyManagerFuzzerWithConfigurationFile(fdp){};
void process() override;
+ void fuzzGetDirectPlaybackSupport();
+
protected:
void setDeviceConnectionState();
void explicitlyRoutingAfterConnection();
@@ -891,10 +893,27 @@
}
}
+void AudioPolicyManagerFuzzerDeviceConnection::fuzzGetDirectPlaybackSupport() {
+ const uint32_t numTestCases = mFdp->ConsumeIntegralInRange<uint32_t>(1, 10);
+ for (int i = 0; i < numTestCases; ++i) {
+ audio_attributes_t attr = AUDIO_ATTRIBUTES_INITIALIZER;
+ attr.content_type = getValueFromVector<audio_content_type_t>(mFdp, kAudioContentTypes);
+ attr.usage = getValueFromVector<audio_usage_t>(mFdp, kAudioUsages);
+ attr.source = getValueFromVector<audio_source_t>(mFdp, kAudioSources);
+ attr.flags = getValueFromVector<audio_flags_mask_t>(mFdp, kAudioFlagMasks);
+ audio_config_t config = AUDIO_CONFIG_INITIALIZER;
+ config.channel_mask = getValueFromVector<audio_channel_mask_t>(mFdp, kAudioChannelOutMasks);
+ config.format = getValueFromVector<audio_format_t>(mFdp, kAudioFormats);
+ config.sample_rate = getValueFromVector<uint32_t>(mFdp, kSamplingRates);
+ mManager->getDirectPlaybackSupport(&attr, &config);
+ }
+}
+
void AudioPolicyManagerFuzzerDeviceConnection::process() {
if (initialize()) {
setDeviceConnectionState();
explicitlyRoutingAfterConnection();
+ fuzzGetDirectPlaybackSupport();
fuzzPatchCreation();
}
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 00c1f26..ee2c0f7 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1386,8 +1386,14 @@
ALOGV("Set VoIP and Direct output flags for PCM format");
}
+ // Attach the Ultrasound flag for the AUDIO_CONTENT_TYPE_ULTRASOUND
+ if (attr->content_type == AUDIO_CONTENT_TYPE_ULTRASOUND) {
+ *flags = (audio_output_flags_t)(*flags | AUDIO_OUTPUT_FLAG_ULTRASOUND);
+ }
+
if (mSpatializerOutput != nullptr
- && canBeSpatialized(attr, config, devices.toTypeAddrVector())) {
+ && canBeSpatializedInt(attr, config,
+ devices.toTypeAddrVector(), false /* allowCurrentOutputReconfig */)) {
return mSpatializerOutput->mIoHandle;
}
@@ -1683,7 +1689,8 @@
// other criteria
static const audio_output_flags_t kFunctionalFlags = (audio_output_flags_t)
(AUDIO_OUTPUT_FLAG_VOIP_RX | AUDIO_OUTPUT_FLAG_INCALL_MUSIC |
- AUDIO_OUTPUT_FLAG_TTS | AUDIO_OUTPUT_FLAG_DIRECT_PCM);
+ AUDIO_OUTPUT_FLAG_TTS | AUDIO_OUTPUT_FLAG_DIRECT_PCM | AUDIO_OUTPUT_FLAG_ULTRASOUND |
+ AUDIO_OUTPUT_FLAG_SPATIALIZER);
// Flags expressing a performance request: have lower priority than serving
// requested sampling rate or channel mask
static const audio_output_flags_t kPerformanceFlags = (audio_output_flags_t)
@@ -1702,6 +1709,8 @@
// The priority is as follows:
// 1: the output supporting haptic playback when requesting haptic playback
// 2: the output with the highest number of requested functional flags
+ // with tiebreak preferring the minimum number of extra functional flags
+ // (see b/200293124, the incorrect selection of AUDIO_OUTPUT_FLAG_VOIP_RX).
// 3: the output supporting the exact channel mask
// 4: the output with a higher channel count than requested
// 5: the output with a higher sampling rate than requested
@@ -1743,7 +1752,12 @@
}
// functional flags match
- currentMatchCriteria[1] = popcount(outputDesc->mFlags & functionalFlags);
+ const int matchingFunctionalFlags =
+ __builtin_popcount(outputDesc->mFlags & functionalFlags);
+ const int totalFunctionalFlags =
+ __builtin_popcount(outputDesc->mFlags & kFunctionalFlags);
+ // Prefer matching functional flags, but subtract unnecessary functional flags.
+ currentMatchCriteria[1] = 100 * (matchingFunctionalFlags + 1) - totalFunctionalFlags;
// channel mask and channel count match
uint32_t outputChannelCount = audio_channel_count_from_out_mask(
@@ -2364,6 +2378,10 @@
flags = (audio_input_flags_t)(flags | AUDIO_INPUT_FLAG_VOIP_TX);
}
+ if (attributes.source == AUDIO_SOURCE_ULTRASOUND) {
+ flags = (audio_input_flags_t)(flags | AUDIO_INPUT_FLAG_ULTRASOUND);
+ }
+
// find a compatible input profile (not necessarily identical in parameters)
sp<IOProfile> profile;
// sampling rate and flags may be updated by getInputProfile
@@ -2380,7 +2398,7 @@
break; // success
} else if (profileFlags & AUDIO_INPUT_FLAG_RAW) {
profileFlags = (audio_input_flags_t) (profileFlags & ~AUDIO_INPUT_FLAG_RAW); // retry
- } else if (profileFlags != AUDIO_INPUT_FLAG_NONE) {
+ } else if (profileFlags != AUDIO_INPUT_FLAG_NONE && audio_is_linear_pcm(config->format)) {
profileFlags = AUDIO_INPUT_FLAG_NONE; // retry
} else { // fail
ALOGW("%s could not find profile for device %s, sampling rate %u, format %#x, "
@@ -3655,53 +3673,7 @@
offloadInfo.stream_type, offloadInfo.bit_rate, offloadInfo.duration_us,
offloadInfo.has_video);
- if (mMasterMono) {
- return AUDIO_OFFLOAD_NOT_SUPPORTED; // no offloading if mono is set.
- }
-
- // Check if offload has been disabled
- if (property_get_bool("audio.offload.disable", false /* default_value */)) {
- ALOGV("%s: offload disabled by audio.offload.disable", __func__);
- return AUDIO_OFFLOAD_NOT_SUPPORTED;
- }
-
- // Check if stream type is music, then only allow offload as of now.
- if (offloadInfo.stream_type != AUDIO_STREAM_MUSIC)
- {
- ALOGV("%s: stream_type != MUSIC, returning false", __func__);
- return AUDIO_OFFLOAD_NOT_SUPPORTED;
- }
-
- //TODO: enable audio offloading with video when ready
- const bool allowOffloadWithVideo =
- property_get_bool("audio.offload.video", false /* default_value */);
- if (offloadInfo.has_video && !allowOffloadWithVideo) {
- ALOGV("%s: has_video == true, returning false", __func__);
- return AUDIO_OFFLOAD_NOT_SUPPORTED;
- }
-
- //If duration is less than minimum value defined in property, return false
- const int min_duration_secs = property_get_int32(
- "audio.offload.min.duration.secs", -1 /* default_value */);
- if (min_duration_secs >= 0) {
- if (offloadInfo.duration_us < min_duration_secs * 1000000LL) {
- ALOGV("%s: Offload denied by duration < audio.offload.min.duration.secs(=%d)",
- __func__, min_duration_secs);
- return AUDIO_OFFLOAD_NOT_SUPPORTED;
- }
- } else if (offloadInfo.duration_us < OFFLOAD_DEFAULT_MIN_DURATION_SECS * 1000000) {
- ALOGV("%s: Offload denied by duration < default min(=%u)",
- __func__, OFFLOAD_DEFAULT_MIN_DURATION_SECS);
- return AUDIO_OFFLOAD_NOT_SUPPORTED;
- }
-
- // Do not allow offloading if one non offloadable effect is enabled. This prevents from
- // creating an offloaded track and tearing it down immediately after start when audioflinger
- // detects there is an active non offloadable effect.
- // FIXME: We should check the audio session here but we do not have it in this context.
- // This may prevent offloading in rare situations where effects are left active by apps
- // in the background.
- if (mEffects.isNonOffloadableEffectEnabled()) {
+ if (!isOffloadPossible(offloadInfo)) {
return AUDIO_OFFLOAD_NOT_SUPPORTED;
}
@@ -3729,7 +3701,8 @@
const audio_attributes_t& attributes) {
audio_output_flags_t output_flags = AUDIO_OUTPUT_FLAG_NONE;
audio_flags_to_audio_output_flags(attributes.flags, &output_flags);
- sp<IOProfile> profile = getProfileForOutput(DeviceVector() /*ignore device */,
+ DeviceVector outputDevices = mEngine->getOutputDevicesForAttributes(attributes);
+ sp<IOProfile> profile = getProfileForOutput(outputDevices,
config.sample_rate,
config.format,
config.channel_mask,
@@ -3743,6 +3716,123 @@
return (profile != 0);
}
+bool AudioPolicyManager::isOffloadPossible(const audio_offload_info_t &offloadInfo,
+ bool durationIgnored) {
+ if (mMasterMono) {
+ return false; // no offloading if mono is set.
+ }
+
+ // Check if offload has been disabled
+ if (property_get_bool("audio.offload.disable", false /* default_value */)) {
+ ALOGV("%s: offload disabled by audio.offload.disable", __func__);
+ return false;
+ }
+
+ // Check if stream type is music, then only allow offload as of now.
+ if (offloadInfo.stream_type != AUDIO_STREAM_MUSIC)
+ {
+ ALOGV("%s: stream_type != MUSIC, returning false", __func__);
+ return false;
+ }
+
+ //TODO: enable audio offloading with video when ready
+ const bool allowOffloadWithVideo =
+ property_get_bool("audio.offload.video", false /* default_value */);
+ if (offloadInfo.has_video && !allowOffloadWithVideo) {
+ ALOGV("%s: has_video == true, returning false", __func__);
+ return false;
+ }
+
+ //If duration is less than minimum value defined in property, return false
+ const int min_duration_secs = property_get_int32(
+ "audio.offload.min.duration.secs", -1 /* default_value */);
+ if (!durationIgnored) {
+ if (min_duration_secs >= 0) {
+ if (offloadInfo.duration_us < min_duration_secs * 1000000LL) {
+ ALOGV("%s: Offload denied by duration < audio.offload.min.duration.secs(=%d)",
+ __func__, min_duration_secs);
+ return false;
+ }
+ } else if (offloadInfo.duration_us < OFFLOAD_DEFAULT_MIN_DURATION_SECS * 1000000) {
+ ALOGV("%s: Offload denied by duration < default min(=%u)",
+ __func__, OFFLOAD_DEFAULT_MIN_DURATION_SECS);
+ return false;
+ }
+ }
+
+ // Do not allow offloading if one non offloadable effect is enabled. This prevents from
+ // creating an offloaded track and tearing it down immediately after start when audioflinger
+ // detects there is an active non offloadable effect.
+ // FIXME: We should check the audio session here but we do not have it in this context.
+ // This may prevent offloading in rare situations where effects are left active by apps
+ // in the background.
+ if (mEffects.isNonOffloadableEffectEnabled()) {
+ return false;
+ }
+
+ return true;
+}
+
+audio_direct_mode_t AudioPolicyManager::getDirectPlaybackSupport(const audio_attributes_t *attr,
+ const audio_config_t *config) {
+ audio_offload_info_t offloadInfo = AUDIO_INFO_INITIALIZER;
+ offloadInfo.format = config->format;
+ offloadInfo.sample_rate = config->sample_rate;
+ offloadInfo.channel_mask = config->channel_mask;
+ offloadInfo.stream_type = mEngine->getStreamTypeForAttributes(*attr);
+ offloadInfo.has_video = false;
+ offloadInfo.is_streaming = false;
+ const bool offloadPossible = isOffloadPossible(offloadInfo, true /*durationIgnored*/);
+
+ audio_direct_mode_t directMode = AUDIO_DIRECT_NOT_SUPPORTED;
+ audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE;
+ audio_flags_to_audio_output_flags(attr->flags, &flags);
+ // only retain flags that will drive compressed offload or passthrough
+ uint32_t relevantFlags = AUDIO_OUTPUT_FLAG_HW_AV_SYNC;
+ if (offloadPossible) {
+ relevantFlags |= AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
+ }
+ flags = (audio_output_flags_t)((flags & relevantFlags) | AUDIO_OUTPUT_FLAG_DIRECT);
+
+ DeviceVector outputDevices = mEngine->getOutputDevicesForAttributes(*attr);
+ for (const auto& hwModule : mHwModules) {
+ for (const auto& curProfile : hwModule->getOutputProfiles()) {
+ if (!curProfile->isCompatibleProfile(outputDevices,
+ config->sample_rate, nullptr /*updatedSamplingRate*/,
+ config->format, nullptr /*updatedFormat*/,
+ config->channel_mask, nullptr /*updatedChannelMask*/,
+ flags)) {
+ continue;
+ }
+ // reject profiles not corresponding to a device currently available
+ if (!mAvailableOutputDevices.containsAtLeastOne(curProfile->getSupportedDevices())) {
+ continue;
+ }
+ if ((curProfile->getFlags() & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)
+ != AUDIO_OUTPUT_FLAG_NONE) {
+ if ((directMode & AUDIO_DIRECT_OFFLOAD_GAPLESS_SUPPORTED)
+ != AUDIO_DIRECT_NOT_SUPPORTED) {
+ // Already reports offload gapless supported. No need to report offload support.
+ continue;
+ }
+ if ((curProfile->getFlags() & AUDIO_OUTPUT_FLAG_GAPLESS_OFFLOAD)
+ != AUDIO_OUTPUT_FLAG_NONE) {
+ // If offload gapless is reported, no need to report offload support.
+ directMode = (audio_direct_mode_t) ((directMode &
+ ~AUDIO_DIRECT_OFFLOAD_SUPPORTED) |
+ AUDIO_DIRECT_OFFLOAD_GAPLESS_SUPPORTED);
+ } else {
+ directMode = (audio_direct_mode_t)(directMode |AUDIO_DIRECT_OFFLOAD_SUPPORTED);
+ }
+ } else {
+ directMode = (audio_direct_mode_t) (directMode |
+ AUDIO_DIRECT_BITSTREAM_SUPPORTED);
+ }
+ }
+ }
+ return directMode;
+}
+
status_t AudioPolicyManager::listAudioPorts(audio_port_role_t role,
audio_port_type_t type,
unsigned int *num_ports,
@@ -4870,9 +4960,10 @@
}
}
-bool AudioPolicyManager::canBeSpatialized(const audio_attributes_t *attr,
+bool AudioPolicyManager::canBeSpatializedInt(const audio_attributes_t *attr,
const audio_config_t *config,
- const AudioDeviceTypeAddrVector &devices) const
+ const AudioDeviceTypeAddrVector &devices,
+ bool allowCurrentOutputReconfig) const
{
// The caller can have the audio attributes criteria ignored by either passing a null ptr or
// the AUDIO_ATTRIBUTES_INITIALIZER value.
@@ -4908,7 +4999,8 @@
if (!isChannelMaskSpatialized(config->channel_mask)) {
return false;
}
- if (mSpatializerOutput != nullptr && mSpatializerOutput->mProfile == profile) {
+ if (!allowCurrentOutputReconfig && mSpatializerOutput != nullptr
+ && mSpatializerOutput->mProfile == profile) {
if ((config->channel_mask & mSpatializerOutput->mMixerChannelMask)
!= config->channel_mask) {
return false;
@@ -4929,7 +5021,8 @@
audio_config_base_t clientConfig = client->config();
audio_config_t config = audio_config_initializer(&clientConfig);
if (desc != mSpatializerOutput
- && canBeSpatialized(&attr, &config, devicesTypeAddress)) {
+ && canBeSpatializedInt(&attr, &config,
+ devicesTypeAddress, false /* allowCurrentOutputReconfig */)) {
streamsToInvalidate.insert(client->stream());
}
}
@@ -4953,7 +5046,8 @@
config = audio_config_initializer(mixerConfig);
configPtr = &config;
}
- if (!canBeSpatialized(attr, configPtr, devicesTypeAddress)) {
+ if (!canBeSpatializedInt(
+ attr, configPtr, devicesTypeAddress)) {
ALOGW("%s provided attributes or mixer config cannot be spatialized", __func__);
return BAD_VALUE;
}
@@ -4976,6 +5070,7 @@
for (size_t i = 0; i < mOutputs.size(); i++) {
sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
if (!desc->isDuplicated() && desc->mProfile == profile) {
+ ALOGV("%s found output %d for spatializer profile", __func__, desc->mIoHandle);
mSpatializerOutput = desc;
break;
}
@@ -4995,39 +5090,29 @@
};
DeviceVector savedDevices = mSpatializerOutput->devices();
- closeOutput(mSpatializerOutput->mIoHandle);
- mSpatializerOutput.clear();
+ ALOGV("%s reopening spatializer output to match channel mask %#x (current mask %#x)",
+ __func__, configPtr->channel_mask, mSpatializerOutput->mMixerChannelMask);
- const sp<SwAudioOutputDescriptor> desc =
- new SwAudioOutputDescriptor(profile, mpClientInterface);
- status_t status = desc->open(nullptr, mixerConfig, devices,
- mEngine->getStreamTypeForAttributes(*attr),
- AUDIO_OUTPUT_FLAG_SPATIALIZER, output);
- if (status != NO_ERROR) {
- ALOGW("%s failed opening output: status %d, output %d", __func__, status, *output);
- if (*output != AUDIO_IO_HANDLE_NONE) {
- desc->close();
- }
+ closeOutput(mSpatializerOutput->mIoHandle);
+ //from now on mSpatializerOutput is null
+
+ sp<SwAudioOutputDescriptor> desc =
+ openOutputWithProfileAndDevice(profile, devices, mixerConfig);
+ if (desc == nullptr) {
// re open the spatializer output with previous channel mask
- status_t newStatus = desc->open(nullptr, &savedMixerConfig, savedDevices,
- mEngine->getStreamTypeForAttributes(*attr),
- AUDIO_OUTPUT_FLAG_SPATIALIZER, output);
- if (newStatus != NO_ERROR) {
- if (*output != AUDIO_IO_HANDLE_NONE) {
- desc->close();
- }
- ALOGE("%s failed to re-open mSpatializerOutput, status %d", __func__, newStatus);
+ desc = openOutputWithProfileAndDevice(profile, savedDevices, &savedMixerConfig);
+ if (desc == nullptr) {
+ ALOGE("%s failed to restore mSpatializerOutput with previous config", __func__);
} else {
mSpatializerOutput = desc;
- addOutput(*output, desc);
}
mPreviousOutputs = mOutputs;
mpClientInterface->onAudioPortListUpdate();
*output = AUDIO_IO_HANDLE_NONE;
- return status;
+ ALOGW("%s could not open spatializer output with requested config", __func__);
+ return BAD_VALUE;
}
mSpatializerOutput = desc;
- addOutput(*output, desc);
mPreviousOutputs = mOutputs;
mpClientInterface->onAudioPortListUpdate();
}
@@ -5103,8 +5188,6 @@
ALOGE("could not load audio policy configuration file, setting defaults");
getConfig().setDefault();
}
- //TODO: b/193496180 use spatializer flag at audio HAL when available
- getConfig().convertSpatializerFlag();
}
status_t AudioPolicyManager::initialize() {
@@ -5220,7 +5303,8 @@
ALOGW("Output profile contains no device on module %s", hwModule->getName());
continue;
}
- if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_TTS) != 0) {
+ if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_TTS) != 0 ||
+ (outProfile->getFlags() & AUDIO_OUTPUT_FLAG_ULTRASOUND) != 0) {
mTtsOutputAvailable = true;
}
@@ -5699,6 +5783,9 @@
removeOutput(output);
mPreviousOutputs = mOutputs;
+ if (closingOutput == mSpatializerOutput) {
+ mSpatializerOutput.clear();
+ }
// MSD patches may have been released to support a non-MSD direct output. Reset MSD patch if
// no direct outputs are open.
@@ -6103,7 +6190,8 @@
return hasVoiceStream(streams) && (outputDesc == mPrimaryOutput ||
outputDesc->isActive(toVolumeSource(AUDIO_STREAM_VOICE_CALL))) &&
(isInCall() ||
- mOutputs.isStrategyActiveOnSameModule(productStrategy, outputDesc));
+ mOutputs.isStrategyActiveOnSameModule(productStrategy, outputDesc)) &&
+ !isStreamActive(AUDIO_STREAM_ENFORCED_AUDIBLE, 0);
};
// With low-latency playing on speaker, music on WFD, when the first low-latency
@@ -7251,7 +7339,8 @@
}
sp<SwAudioOutputDescriptor> AudioPolicyManager::openOutputWithProfileAndDevice(
- const sp<IOProfile>& profile, const DeviceVector& devices)
+ const sp<IOProfile>& profile, const DeviceVector& devices,
+ const audio_config_base_t *mixerConfig)
{
for (const auto& device : devices) {
// TODO: This should be checking if the profile supports the device combo.
@@ -7261,7 +7350,7 @@
}
sp<SwAudioOutputDescriptor> desc = new SwAudioOutputDescriptor(profile, mpClientInterface);
audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
- status_t status = desc->open(nullptr /* halConfig */, nullptr /* mixerConfig */, devices,
+ status_t status = desc->open(nullptr /* halConfig */, mixerConfig, devices,
AUDIO_STREAM_DEFAULT, AUDIO_OUTPUT_FLAG_NONE, &output);
if (status != NO_ERROR) {
return nullptr;
@@ -7291,7 +7380,7 @@
config.offload_info.channel_mask = config.channel_mask;
config.offload_info.format = config.format;
- status = desc->open(&config, nullptr /* mixerConfig */, devices,
+ status = desc->open(&config, mixerConfig, devices,
AUDIO_STREAM_DEFAULT, AUDIO_OUTPUT_FLAG_NONE, &output);
if (status != NO_ERROR) {
return nullptr;
@@ -7299,6 +7388,7 @@
}
addOutput(output, desc);
+
if (audio_is_remote_submix_device(deviceType) && address != "0") {
sp<AudioPolicyMix> policyMix;
if (mPolicyMixes.getAudioPolicyMix(deviceType, address, policyMix) == NO_ERROR) {
@@ -7309,9 +7399,13 @@
address.string());
}
- } else if (((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) && hasPrimaryOutput()) {
- // no duplicated output for direct outputs and
- // outputs used by dynamic policy mixes
+ } else if (hasPrimaryOutput() && profile->getModule()
+ != mHwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY)
+ && ((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0)) {
+ // no duplicated output for:
+ // - direct outputs
+ // - outputs used by dynamic policy mixes
+ // - outputs opened on the primary HW module
audio_io_handle_t duplicatedOutput = AUDIO_IO_HANDLE_NONE;
//TODO: configure audio effect output stage here
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 8a85b95..dd69295 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -358,7 +358,9 @@
virtual bool canBeSpatialized(const audio_attributes_t *attr,
const audio_config_t *config,
- const AudioDeviceTypeAddrVector &devices) const;
+ const AudioDeviceTypeAddrVector &devices) const {
+ return canBeSpatializedInt(attr, config, devices);
+ }
virtual status_t getSpatializerOutput(const audio_config_base_t *config,
const audio_attributes_t *attr,
@@ -366,6 +368,9 @@
virtual status_t releaseSpatializerOutput(audio_io_handle_t output);
+ virtual audio_direct_mode_t getDirectPlaybackSupport(const audio_attributes_t *attr,
+ const audio_config_t *config);
+
bool isCallScreenModeSupported() override;
void onNewAudioModulesAvailable() override;
@@ -854,7 +859,8 @@
uint32_t mBeaconMuteRefCount; // ref count for stream that would mute beacon
uint32_t mBeaconPlayingRefCount;// ref count for the playing beacon streams
bool mBeaconMuted; // has STREAM_TTS been muted
- bool mTtsOutputAvailable; // true if a dedicated output for TTS stream is available
+ // true if a dedicated output for TTS stream or Ultrasound is available
+ bool mTtsOutputAvailable;
bool mMasterMono; // true if we wish to force all outputs to mono
AudioPolicyMixCollection mPolicyMixes; // list of registered mixes
@@ -961,6 +967,30 @@
const DeviceVector &devices,
audio_io_handle_t *output);
+ /**
+ * @brief Queries if some kind of spatialization will be performed if the audio playback
+ * context described by the provided arguments is present.
+ * The context is made of:
+ * - The audio attributes describing the playback use case.
+ * - The audio configuration describing the audio format, channels, sampling rate ...
+ * - The devices describing the sink audio device selected for playback.
+ * All arguments are optional and only the specified arguments are used to match against
+ * supported criteria. For instance, supplying no argument will tell if spatialization is
+ * supported or not in general.
+ * @param attr audio attributes describing the playback use case
+ * @param config audio configuration describing the audio format, channels, sample rate...
+ * @param devices the sink audio device selected for playback
+ * @param allowCurrentOutputReconfig if true, the result will be considering it is possible
+ * to close and reopen an existing spatializer output stream to match the requested
+ * criteria. If false, the criteria must be compatible with the opened sptializer
+ * output.
+ * @return true if spatialization is possible for this context, false otherwise.
+ */
+ virtual bool canBeSpatializedInt(const audio_attributes_t *attr,
+ const audio_config_t *config,
+ const AudioDeviceTypeAddrVector &devices,
+ bool allowCurrentOutputReconfig = true) const;
+
sp<IOProfile> getSpatializerOutputProfile(const audio_config_t *config,
const AudioDeviceTypeAddrVector &devices) const;
@@ -1056,8 +1086,23 @@
bool areAllActiveTracksRerouted(const sp<SwAudioOutputDescriptor>& output);
- sp<SwAudioOutputDescriptor> openOutputWithProfileAndDevice(const sp<IOProfile>& profile,
- const DeviceVector& devices);
+ /**
+ * @brief Opens an output stream from the supplied IOProfile and route it to the
+ * supplied audio devices. If a mixer config is specified, it is forwarded to audio
+ * flinger. If not, a default config is derived from the output stream config.
+ * Also opens a duplicating output if needed and queries the audio HAL for supported
+ * audio profiles if the IOProfile is dynamic.
+ * @param[in] profile IOProfile to use as template
+ * @param[in] devices initial route to apply to this output stream
+ * @param[in] mixerConfig if not null, use this to configure the mixer
+ * @return an output descriptor for the newly opened stream or null in case of error.
+ */
+ sp<SwAudioOutputDescriptor> openOutputWithProfileAndDevice(
+ const sp<IOProfile>& profile, const DeviceVector& devices,
+ const audio_config_base_t *mixerConfig = nullptr);
+
+ bool isOffloadPossible(const audio_offload_info_t& offloadInfo,
+ bool durationIgnored = false);
};
diff --git a/services/audiopolicy/service/AudioPolicyEffects.cpp b/services/audiopolicy/service/AudioPolicyEffects.cpp
index 3f01de9..858a3fd 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.cpp
+++ b/services/audiopolicy/service/AudioPolicyEffects.cpp
@@ -345,7 +345,8 @@
(source > AUDIO_SOURCE_MAX &&
source != AUDIO_SOURCE_HOTWORD &&
source != AUDIO_SOURCE_FM_TUNER &&
- source != AUDIO_SOURCE_ECHO_REFERENCE)) {
+ source != AUDIO_SOURCE_ECHO_REFERENCE &&
+ source != AUDIO_SOURCE_ULTRASOUND)) {
ALOGE("addSourceDefaultEffect(): Unsupported source type %d", source);
return BAD_VALUE;
}
@@ -544,6 +545,7 @@
CAMCORDER_SRC_TAG,
VOICE_REC_SRC_TAG,
VOICE_COMM_SRC_TAG,
+ REMOTE_SUBMIX_SRC_TAG,
UNPROCESSED_SRC_TAG,
VOICE_PERFORMANCE_SRC_TAG
};
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 1fbea7d..a30768a 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -376,6 +376,15 @@
attr.flags = static_cast<audio_flags_mask_t>(
attr.flags & ~(AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY|AUDIO_FLAG_BYPASS_MUTE));
}
+
+ if (attr.content_type == AUDIO_CONTENT_TYPE_ULTRASOUND) {
+ if (!accessUltrasoundAllowed(adjAttributionSource)) {
+ ALOGE("%s: permission denied: ultrasound not allowed for uid %d pid %d",
+ __func__, adjAttributionSource.uid, adjAttributionSource.pid);
+ return binderStatusFromStatusT(PERMISSION_DENIED);
+ }
+ }
+
AutoCallerClear acc;
AudioPolicyInterface::output_type_t outputType;
status_t result = mAudioPolicyManager->getOutputForAttr(&attr, &output, session,
@@ -596,7 +605,8 @@
|| (inputSource >= AUDIO_SOURCE_CNT
&& inputSource != AUDIO_SOURCE_HOTWORD
&& inputSource != AUDIO_SOURCE_FM_TUNER
- && inputSource != AUDIO_SOURCE_ECHO_REFERENCE)) {
+ && inputSource != AUDIO_SOURCE_ECHO_REFERENCE
+ && inputSource != AUDIO_SOURCE_ULTRASOUND)) {
return binderStatusFromStatusT(BAD_VALUE);
}
@@ -677,6 +687,14 @@
return binderStatusFromStatusT(PERMISSION_DENIED);
}
+ if (attr.source == AUDIO_SOURCE_ULTRASOUND) {
+ if (!accessUltrasoundAllowed(adjAttributionSource)) {
+ ALOGE("%s: permission denied: ultrasound not allowed for uid %d pid %d",
+ __func__, adjAttributionSource.uid, adjAttributionSource.pid);
+ return binderStatusFromStatusT(PERMISSION_DENIED);
+ }
+ }
+
sp<AudioPolicyEffects>audioPolicyEffects;
{
status_t status;
@@ -2334,4 +2352,24 @@
return Status::ok();
}
+Status AudioPolicyService::getDirectPlaybackSupport(const media::AudioAttributesInternal &attrAidl,
+ const AudioConfig &configAidl,
+ media::AudioDirectMode *_aidl_return) {
+ if (mAudioPolicyManager == nullptr) {
+ return binderStatusFromStatusT(NO_INIT);
+ }
+ if (_aidl_return == nullptr) {
+ return binderStatusFromStatusT(BAD_VALUE);
+ }
+ audio_attributes_t attr = VALUE_OR_RETURN_BINDER_STATUS(
+ aidl2legacy_AudioAttributesInternal_audio_attributes_t(attrAidl));
+ audio_config_t config = VALUE_OR_RETURN_BINDER_STATUS(
+ aidl2legacy_AudioConfig_audio_config_t(configAidl, false /*isInput*/));
+ Mutex::Autolock _l(mLock);
+ *_aidl_return = static_cast<media::AudioDirectMode>(
+ VALUE_OR_RETURN_BINDER_STATUS(legacy2aidl_audio_direct_mode_t_int32_t_mask(
+ mAudioPolicyManager->getDirectPlaybackSupport(&attr, &config))));
+ return Status::ok();
+}
+
} // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index ef7a83b..8add137 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -392,7 +392,8 @@
audio_config_base_t config = mSpatializer->getAudioInConfig();
status_t status =
mAudioPolicyManager->getSpatializerOutput(&config, &attr, &newOutput);
-
+ ALOGV("%s currentOutput %d newOutput %d channel_mask %#x",
+ __func__, currentOutput, newOutput, config.channel_mask);
if (status == NO_ERROR && currentOutput == newOutput) {
return;
}
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index b3ac21b..84b1e50 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -272,6 +272,10 @@
const std::vector<AudioDevice>& devices,
bool* _aidl_return) override;
+ binder::Status getDirectPlaybackSupport(const media::AudioAttributesInternal& attr,
+ const AudioConfig& config,
+ media::AudioDirectMode* _aidl_return) override;
+
status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) override;
// IBinder::DeathRecipient
diff --git a/services/audiopolicy/service/Spatializer.cpp b/services/audiopolicy/service/Spatializer.cpp
index 0fdbe20..54d9094 100644
--- a/services/audiopolicy/service/Spatializer.cpp
+++ b/services/audiopolicy/service/Spatializer.cpp
@@ -227,12 +227,8 @@
if (status != NO_ERROR) {
return status;
}
- status = getHalParameter<true>(effect, SPATIALIZER_PARAM_SUPPORTED_CHANNEL_MASKS,
+ return getHalParameter<true>(effect, SPATIALIZER_PARAM_SUPPORTED_CHANNEL_MASKS,
&mChannelMasks);
- if (status != NO_ERROR) {
- return status;
- }
- return NO_ERROR;
}
/** Gets the channel mask, sampling rate and format set for the spatializer input. */
diff --git a/services/audiopolicy/service/SpatializerPoseController.cpp b/services/audiopolicy/service/SpatializerPoseController.cpp
index ffedf63..440a7ff 100644
--- a/services/audiopolicy/service/SpatializerPoseController.cpp
+++ b/services/audiopolicy/service/SpatializerPoseController.cpp
@@ -35,24 +35,24 @@
namespace {
// This is how fast, in m/s, we allow position to shift during rate-limiting.
-constexpr auto kMaxTranslationalVelocity = 2;
+constexpr float kMaxTranslationalVelocity = 2;
// This is how fast, in rad/s, we allow rotation angle to shift during rate-limiting.
-constexpr auto kMaxRotationalVelocity = 4 * M_PI;
+constexpr float kMaxRotationalVelocity = 8;
// This should be set to the typical time scale that the translation sensors used drift in. This
// means, loosely, for how long we can trust the reading to be "accurate enough". This would
// determine the time constants used for high-pass filtering those readings. If the value is set
// too high, we may experience drift. If it is set too low, we may experience poses tending toward
// identity too fast.
-constexpr auto kTranslationalDriftTimeConstant = 20s;
+constexpr auto kTranslationalDriftTimeConstant = 40s;
// This should be set to the typical time scale that the rotation sensors used drift in. This
// means, loosely, for how long we can trust the reading to be "accurate enough". This would
// determine the time constants used for high-pass filtering those readings. If the value is set
// too high, we may experience drift. If it is set too low, we may experience poses tending toward
// identity too fast.
-constexpr auto kRotationalDriftTimeConstant = 20s;
+constexpr auto kRotationalDriftTimeConstant = 60s;
// This is how far into the future we predict the head pose, using linear extrapolation based on
// twist (velocity). It should be set to a value that matches the characteristic durations of moving
@@ -64,6 +64,25 @@
// stale;
constexpr auto kMaxLostSamples = 4;
+// Auto-recenter kicks in after the head has been still for this long.
+constexpr auto kAutoRecenterWindowDuration = 6s;
+
+// Auto-recenter considers head not still if translated by this much (in meters, approx).
+constexpr float kAutoRecenterTranslationThreshold = 0.1f;
+
+// Auto-recenter considers head not still if rotated by this much (in radians, approx).
+constexpr float kAutoRecenterRotationThreshold = 7.0f / 180 * M_PI;
+
+// Screen is considered to be unstable (not still) if it has moved significantly within the last
+// time window of this duration.
+constexpr auto kScreenStillnessWindowDuration = 3s;
+
+// Screen is considered to have moved significantly if translated by this much (in meter, approx).
+constexpr float kScreenStillnessTranslationThreshold = 0.1f;
+
+// Screen is considered to have moved significantly if rotated by this much (in radians, approx).
+constexpr float kScreenStillnessRotationThreshold = 7.0f / 180 * M_PI;
+
// Time units for system clock ticks. This is what the Sensor Framework timestamps represent and
// what we use for pose filtering.
using Ticks = std::chrono::nanoseconds;
@@ -81,10 +100,17 @@
mProcessor(createHeadTrackingProcessor(HeadTrackingProcessor::Options{
.maxTranslationalVelocity = kMaxTranslationalVelocity / kTicksPerSecond,
.maxRotationalVelocity = kMaxRotationalVelocity / kTicksPerSecond,
- .translationalDriftTimeConstant = Ticks(kTranslationalDriftTimeConstant).count(),
- .rotationalDriftTimeConstant = Ticks(kRotationalDriftTimeConstant).count(),
+ .translationalDriftTimeConstant =
+ double(Ticks(kTranslationalDriftTimeConstant).count()),
+ .rotationalDriftTimeConstant = double(Ticks(kRotationalDriftTimeConstant).count()),
.freshnessTimeout = Ticks(sensorPeriod * kMaxLostSamples).count(),
.predictionDuration = Ticks(kPredictionDuration).count(),
+ .autoRecenterWindowDuration = Ticks(kAutoRecenterWindowDuration).count(),
+ .autoRecenterTranslationalThreshold = kAutoRecenterTranslationThreshold,
+ .autoRecenterRotationalThreshold = kAutoRecenterRotationThreshold,
+ .screenStillnessWindowDuration = Ticks(kScreenStillnessWindowDuration).count(),
+ .screenStillnessTranslationalThreshold = kScreenStillnessTranslationThreshold,
+ .screenStillnessRotationalThreshold = kScreenStillnessRotationThreshold,
})),
mPoseProvider(SensorPoseProvider::create("headtracker", this)),
mThread([this, maxUpdatePeriod] {
diff --git a/services/audiopolicy/tests/AudioPolicyTestManager.h b/services/audiopolicy/tests/AudioPolicyTestManager.h
index 7f67940..9d0d558 100644
--- a/services/audiopolicy/tests/AudioPolicyTestManager.h
+++ b/services/audiopolicy/tests/AudioPolicyTestManager.h
@@ -33,6 +33,7 @@
using AudioPolicyManager::releaseMsdOutputPatches;
using AudioPolicyManager::setMsdOutputPatches;
using AudioPolicyManager::getAudioPatches;
+ using AudioPolicyManager::getDirectPlaybackSupport;
uint32_t getAudioPortGeneration() const { return mAudioPortGeneration; }
};
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp
index 96da0ab..8428881 100644
--- a/services/camera/libcameraservice/Android.bp
+++ b/services/camera/libcameraservice/Android.bp
@@ -47,8 +47,8 @@
"common/CameraDeviceBase.cpp",
"common/CameraOfflineSessionBase.cpp",
"common/CameraProviderManager.cpp",
- "common/DepthPhotoProcessor.cpp",
"common/FrameProcessorBase.cpp",
+ "common/hidl/HidlProviderInfo.cpp",
"api1/Camera2Client.cpp",
"api1/client2/Parameters.cpp",
"api1/client2/FrameProcessor.cpp",
@@ -76,15 +76,14 @@
"device3/StatusTracker.cpp",
"device3/Camera3BufferManager.cpp",
"device3/Camera3StreamSplitter.cpp",
- "device3/CoordinateMapper.cpp",
- "device3/DistortionMapper.cpp",
- "device3/ZoomRatioMapper.cpp",
- "device3/RotateAndCropMapper.cpp",
"device3/Camera3OutputStreamInterface.cpp",
"device3/Camera3OutputUtils.cpp",
"device3/Camera3DeviceInjectionMethods.cpp",
"device3/UHRCropAndMeteringRegionMapper.cpp",
"device3/PreviewFrameScheduler.cpp",
+ "device3/hidl/HidlCamera3Device.cpp",
+ "device3/hidl/HidlCamera3OfflineSession.cpp",
+ "device3/hidl/HidlCamera3OutputUtils.cpp",
"gui/RingBufferConsumer.cpp",
"hidl/AidlCameraDeviceCallbacks.cpp",
"hidl/AidlCameraServiceListener.cpp",
@@ -95,7 +94,6 @@
"utils/CameraThreadState.cpp",
"utils/CameraTraces.cpp",
"utils/AutoConditionLock.cpp",
- "utils/ExifUtils.cpp",
"utils/SessionConfigurationUtils.cpp",
"utils/SessionStatsBuilder.cpp",
"utils/TagMonitor.cpp",
@@ -164,6 +162,7 @@
"libprocessinfoservice_aidl",
"libbinderthreadstateutils",
"media_permission-aidl-cpp",
+ "libcameraservice_device_independent",
],
export_shared_lib_headers: [
@@ -193,3 +192,49 @@
],
}
+
+cc_library_static {
+ name: "libcameraservice_device_independent",
+ host_supported: true,
+
+ // Camera service source
+
+ srcs: [
+ "common/DepthPhotoProcessor.cpp",
+ "device3/CoordinateMapper.cpp",
+ "device3/DistortionMapper.cpp",
+ "device3/RotateAndCropMapper.cpp",
+ "device3/ZoomRatioMapper.cpp",
+ "utils/ExifUtils.cpp",
+ "utils/SessionConfigurationUtilsHost.cpp",
+ ],
+
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "libcamera_metadata",
+ "libdynamic_depth",
+ "libexif",
+ "libjpeg",
+ "liblog",
+ "libutils",
+ "libxml2",
+ ],
+
+ include_dirs: [
+ "external/dynamic_depth/includes",
+ "external/dynamic_depth/internal",
+ "frameworks/av/camera/include",
+ "frameworks/av/camera/include/camera",
+ ],
+
+ export_include_dirs: ["."],
+
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-Wno-ignored-qualifiers",
+ ],
+
+}
\ No newline at end of file
diff --git a/services/camera/libcameraservice/CameraFlashlight.cpp b/services/camera/libcameraservice/CameraFlashlight.cpp
index ccdd9e5..ffd38be 100644
--- a/services/camera/libcameraservice/CameraFlashlight.cpp
+++ b/services/camera/libcameraservice/CameraFlashlight.cpp
@@ -32,8 +32,6 @@
namespace android {
-using hardware::camera::common::V1_0::TorchModeStatus;
-
/////////////////////////////////////////////////////////////////////
// CameraFlashlight implementation begins
// used by camera service to control flashflight.
@@ -119,6 +117,59 @@
return res;
}
+status_t CameraFlashlight::turnOnTorchWithStrengthLevel(const String8& cameraId,
+ int32_t torchStrength) {
+ if (!mFlashlightMapInitialized) {
+ ALOGE("%s: findFlashUnits() must be called before this method.",
+ __FUNCTION__);
+ return NO_INIT;
+ }
+
+ ALOGV("%s: set torch strength of camera %s to %d", __FUNCTION__,
+ cameraId.string(), torchStrength);
+ status_t res = OK;
+ Mutex::Autolock l(mLock);
+
+ if (mOpenedCameraIds.indexOf(cameraId) != NAME_NOT_FOUND) {
+ ALOGE("%s: Camera device %s is in use, cannot be turned ON.",
+ __FUNCTION__, cameraId.string());
+ return -EBUSY;
+ }
+
+ if (mFlashControl == NULL) {
+ res = createFlashlightControl(cameraId);
+ if (res) {
+ return res;
+ }
+ }
+
+ res = mFlashControl->turnOnTorchWithStrengthLevel(cameraId, torchStrength);
+ return res;
+}
+
+
+status_t CameraFlashlight::getTorchStrengthLevel(const String8& cameraId,
+ int32_t* torchStrength) {
+ status_t res = OK;
+ if (!mFlashlightMapInitialized) {
+ ALOGE("%s: findFlashUnits() must be called before this method.",
+ __FUNCTION__);
+ return false;
+ }
+
+ Mutex::Autolock l(mLock);
+
+ if (mFlashControl == NULL) {
+ res = createFlashlightControl(cameraId);
+ if (res) {
+ return res;
+ }
+ }
+
+ res = mFlashControl->getTorchStrengthLevel(cameraId, torchStrength);
+ return res;
+}
+
status_t CameraFlashlight::findFlashUnits() {
Mutex::Autolock l(mLock);
status_t res;
@@ -306,6 +357,22 @@
return mProviderManager->setTorchMode(cameraId.string(), enabled);
}
+
+status_t ProviderFlashControl::turnOnTorchWithStrengthLevel(const String8& cameraId,
+ int32_t torchStrength) {
+ ALOGV("%s: change torch strength level of camera %s to %d", __FUNCTION__,
+ cameraId.string(), torchStrength);
+
+ return mProviderManager->turnOnTorchWithStrengthLevel(cameraId.string(), torchStrength);
+}
+
+status_t ProviderFlashControl::getTorchStrengthLevel(const String8& cameraId,
+ int32_t* torchStrength) {
+ ALOGV("%s: get torch strength level of camera %s", __FUNCTION__,
+ cameraId.string());
+
+ return mProviderManager->getTorchStrengthLevel(cameraId.string(), torchStrength);
+}
// ProviderFlashControl implementation ends
}
diff --git a/services/camera/libcameraservice/CameraFlashlight.h b/services/camera/libcameraservice/CameraFlashlight.h
index b97fa5f..1703ddc 100644
--- a/services/camera/libcameraservice/CameraFlashlight.h
+++ b/services/camera/libcameraservice/CameraFlashlight.h
@@ -44,6 +44,14 @@
// set the torch mode to on or off.
virtual status_t setTorchMode(const String8& cameraId,
bool enabled) = 0;
+
+ // Change the brightness level of the torch. If the torch is OFF and
+ // torchStrength >= 1, then the torch will also be turned ON.
+ virtual status_t turnOnTorchWithStrengthLevel(const String8& cameraId,
+ int32_t torchStrength) = 0;
+
+ // Returns the torch strength level.
+ virtual status_t getTorchStrengthLevel(const String8& cameraId, int32_t* torchStrength) = 0;
};
/**
@@ -67,6 +75,12 @@
// set the torch mode to on or off.
status_t setTorchMode(const String8& cameraId, bool enabled);
+ // Change the torch strength level of the flash unit in torch mode.
+ status_t turnOnTorchWithStrengthLevel(const String8& cameraId, int32_t torchStrength);
+
+ // Get the torch strength level
+ status_t getTorchStrengthLevel(const String8& cameraId, int32_t* torchStrength);
+
// Notify CameraFlashlight that camera service is going to open a camera
// device. CameraFlashlight will free the resources that may cause the
// camera open to fail. Camera service must call this function before
@@ -115,6 +129,8 @@
// FlashControlBase
status_t hasFlashUnit(const String8& cameraId, bool *hasFlash);
status_t setTorchMode(const String8& cameraId, bool enabled);
+ status_t turnOnTorchWithStrengthLevel(const String8& cameraId, int32_t torchStrength);
+ status_t getTorchStrengthLevel(const String8& cameraId, int32_t* torchStrength);
private:
sp<CameraProviderManager> mProviderManager;
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 569ab63..5740038 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -86,13 +86,11 @@
using base::StringPrintf;
using binder::Status;
-using camera3::SessionConfigurationUtils;
+using namespace camera3;
using frameworks::cameraservice::service::V2_0::implementation::HidlCameraService;
using hardware::ICamera;
using hardware::ICameraClient;
using hardware::ICameraServiceListener;
-using hardware::camera::common::V1_0::CameraDeviceStatus;
-using hardware::camera::common::V1_0::TorchModeStatus;
using hardware::camera2::ICameraInjectionCallback;
using hardware::camera2::ICameraInjectionSession;
using hardware::camera2::utils::CameraIdAndSessionConfiguration;
@@ -363,18 +361,20 @@
void CameraService::addStates(const String8 id) {
std::string cameraId(id.c_str());
- hardware::camera::common::V1_0::CameraResourceCost cost;
+ CameraResourceCost cost;
status_t res = mCameraProviderManager->getResourceCost(cameraId, &cost);
- SystemCameraKind deviceKind = SystemCameraKind::PUBLIC;
if (res != OK) {
ALOGE("Failed to query device resource cost: %s (%d)", strerror(-res), res);
return;
}
+ SystemCameraKind deviceKind = SystemCameraKind::PUBLIC;
res = mCameraProviderManager->getSystemCameraKind(cameraId, &deviceKind);
if (res != OK) {
ALOGE("Failed to query device kind: %s (%d)", strerror(-res), res);
return;
}
+ std::vector<std::string> physicalCameraIds;
+ mCameraProviderManager->isLogicalCamera(cameraId, &physicalCameraIds);
std::set<String8> conflicting;
for (size_t i = 0; i < cost.conflictingDevices.size(); i++) {
conflicting.emplace(String8(cost.conflictingDevices[i].c_str()));
@@ -383,7 +383,7 @@
{
Mutex::Autolock lock(mCameraStatesLock);
mCameraStates.emplace(id, std::make_shared<CameraState>(id, cost.resourceCost,
- conflicting, deviceKind));
+ conflicting, deviceKind, physicalCameraIds));
}
if (mFlashlight->hasFlashUnit(id)) {
@@ -569,6 +569,15 @@
onTorchStatusChangedLocked(cameraId, newStatus, systemCameraKind);
}
+void CameraService::broadcastTorchStrengthLevel(const String8& cameraId,
+ int32_t newStrengthLevel) {
+ Mutex::Autolock lock(mStatusListenerLock);
+ for (auto& i : mListenerList) {
+ i->getListener()->onTorchStrengthLevelChanged(String16{cameraId},
+ newStrengthLevel);
+ }
+}
+
void CameraService::onTorchStatusChangedLocked(const String8& cameraId,
TorchModeStatus newStatus, SystemCameraKind systemCameraKind) {
ALOGI("%s: Torch status changed for cameraId=%s, newStatus=%d",
@@ -804,6 +813,31 @@
return ret;
}
+Status CameraService::getTorchStrengthLevel(const String16& cameraId,
+ int32_t* torchStrength) {
+ ATRACE_CALL();
+ Mutex::Autolock l(mServiceLock);
+ if (!mInitialized) {
+ ALOGE("%s: Camera HAL couldn't be initialized.", __FUNCTION__);
+ return STATUS_ERROR(ERROR_DISCONNECTED, "Camera HAL couldn't be initialized.");
+ }
+
+ if(torchStrength == NULL) {
+ ALOGE("%s: strength level must not be null.", __FUNCTION__);
+ return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, "Strength level should not be null.");
+ }
+
+ status_t res = mCameraProviderManager->getTorchStrengthLevel(String8(cameraId).string(),
+ torchStrength);
+ if (res != OK) {
+ return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION, "Unable to retrieve torch "
+ "strength level for device %s: %s (%d)", String8(cameraId).string(),
+ strerror(-res), res);
+ }
+ ALOGI("%s: Torch strength level is: %d", __FUNCTION__, *torchStrength);
+ return Status::ok();
+}
+
String8 CameraService::getFormattedCurrentTime() {
time_t now = time(nullptr);
char formattedTime[64];
@@ -1848,8 +1882,10 @@
if (mOverrideRotateAndCropMode != ANDROID_SCALER_ROTATE_AND_CROP_AUTO) {
client->setRotateAndCropOverride(mOverrideRotateAndCropMode);
} else if (effectiveApiLevel == API_2) {
- client->setRotateAndCropOverride(CameraServiceProxyWrapper::getRotateAndCropOverride(
- clientPackageName, facing));
+
+ client->setRotateAndCropOverride(
+ CameraServiceProxyWrapper::getRotateAndCropOverride(
+ clientPackageName, facing, multiuser_get_user_id(clientUid)));
}
// Set camera muting behavior
@@ -2004,6 +2040,132 @@
return OK;
}
+Status CameraService::turnOnTorchWithStrengthLevel(const String16& cameraId, int32_t torchStrength,
+ const sp<IBinder>& clientBinder) {
+ Mutex::Autolock lock(mServiceLock);
+
+ ATRACE_CALL();
+ if (clientBinder == nullptr) {
+ ALOGE("%s: torch client binder is NULL", __FUNCTION__);
+ return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT,
+ "Torch client binder in null.");
+ }
+
+ String8 id = String8(cameraId.string());
+ int uid = CameraThreadState::getCallingUid();
+
+ if (shouldRejectSystemCameraConnection(id)) {
+ return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT, "Unable to change the strength level"
+ "for system only device %s: ", id.string());
+ }
+
+ // verify id is valid
+ auto state = getCameraState(id);
+ if (state == nullptr) {
+ ALOGE("%s: camera id is invalid %s", __FUNCTION__, id.string());
+ return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT,
+ "Camera ID \"%s\" is a not valid camera ID", id.string());
+ }
+
+ StatusInternal cameraStatus = state->getStatus();
+ if (cameraStatus != StatusInternal::NOT_AVAILABLE &&
+ cameraStatus != StatusInternal::PRESENT) {
+ ALOGE("%s: camera id is invalid %s, status %d", __FUNCTION__, id.string(),
+ (int)cameraStatus);
+ return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT,
+ "Camera ID \"%s\" is a not valid camera ID", id.string());
+ }
+
+ {
+ Mutex::Autolock al(mTorchStatusMutex);
+ TorchModeStatus status;
+ status_t err = getTorchStatusLocked(id, &status);
+ if (err != OK) {
+ if (err == NAME_NOT_FOUND) {
+ return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT,
+ "Camera \"%s\" does not have a flash unit", id.string());
+ }
+ ALOGE("%s: getting current torch status failed for camera %s",
+ __FUNCTION__, id.string());
+ return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
+ "Error changing torch strength level for camera \"%s\": %s (%d)",
+ id.string(), strerror(-err), err);
+ }
+
+ if (status == TorchModeStatus::NOT_AVAILABLE) {
+ if (cameraStatus == StatusInternal::NOT_AVAILABLE) {
+ ALOGE("%s: torch mode of camera %s is not available because "
+ "camera is in use.", __FUNCTION__, id.string());
+ return STATUS_ERROR_FMT(ERROR_CAMERA_IN_USE,
+ "Torch for camera \"%s\" is not available due to an existing camera user",
+ id.string());
+ } else {
+ ALOGE("%s: torch mode of camera %s is not available due to "
+ "insufficient resources", __FUNCTION__, id.string());
+ return STATUS_ERROR_FMT(ERROR_MAX_CAMERAS_IN_USE,
+ "Torch for camera \"%s\" is not available due to insufficient resources",
+ id.string());
+ }
+ }
+ }
+
+ {
+ Mutex::Autolock al(mTorchUidMapMutex);
+ updateTorchUidMapLocked(cameraId, uid);
+ }
+ // Check if the current torch strength level is same as the new one.
+ bool shouldSkipTorchStrengthUpdates = mCameraProviderManager->shouldSkipTorchStrengthUpdate(
+ id.string(), torchStrength);
+
+ status_t err = mFlashlight->turnOnTorchWithStrengthLevel(id, torchStrength);
+
+ if (err != OK) {
+ int32_t errorCode;
+ String8 msg;
+ switch (err) {
+ case -ENOSYS:
+ msg = String8::format("Camera \"%s\" has no flashlight.",
+ id.string());
+ errorCode = ERROR_ILLEGAL_ARGUMENT;
+ break;
+ case -EBUSY:
+ msg = String8::format("Camera \"%s\" is in use",
+ id.string());
+ errorCode = ERROR_CAMERA_IN_USE;
+ break;
+ default:
+ msg = String8::format("Changing torch strength level failed.");
+ errorCode = ERROR_INVALID_OPERATION;
+
+ }
+ ALOGE("%s: %s", __FUNCTION__, msg.string());
+ return STATUS_ERROR(errorCode, msg.string());
+ }
+
+ {
+ // update the link to client's death
+ // Store the last client that turns on each camera's torch mode.
+ Mutex::Autolock al(mTorchClientMapMutex);
+ ssize_t index = mTorchClientMap.indexOfKey(id);
+ if (index == NAME_NOT_FOUND) {
+ mTorchClientMap.add(id, clientBinder);
+ } else {
+ mTorchClientMap.valueAt(index)->unlinkToDeath(this);
+ mTorchClientMap.replaceValueAt(index, clientBinder);
+ }
+ clientBinder->linkToDeath(this);
+ }
+
+ int clientPid = CameraThreadState::getCallingPid();
+ const char *id_cstr = id.c_str();
+ ALOGI("%s: Torch strength for camera id %s changed to %d for client PID %d",
+ __FUNCTION__, id_cstr, torchStrength, clientPid);
+ if (!shouldSkipTorchStrengthUpdates) {
+ broadcastTorchStrengthLevel(id, torchStrength);
+ }
+ return Status::ok();
+}
+
Status CameraService::setTorchMode(const String16& cameraId, bool enabled,
const sp<IBinder>& clientBinder) {
Mutex::Autolock lock(mServiceLock);
@@ -2075,13 +2237,7 @@
// Update UID map - this is used in the torch status changed callbacks, so must be done
// before setTorchMode
Mutex::Autolock al(mTorchUidMapMutex);
- if (mTorchUidMap.find(id) == mTorchUidMap.end()) {
- mTorchUidMap[id].first = uid;
- mTorchUidMap[id].second = uid;
- } else {
- // Set the pending UID
- mTorchUidMap[id].first = uid;
- }
+ updateTorchUidMapLocked(cameraId, uid);
}
status_t err = mFlashlight->setTorchMode(id, enabled);
@@ -2136,6 +2292,17 @@
return Status::ok();
}
+void CameraService::updateTorchUidMapLocked(const String16& cameraId, int uid) {
+ String8 id = String8(cameraId.string());
+ if (mTorchUidMap.find(id) == mTorchUidMap.end()) {
+ mTorchUidMap[id].first = uid;
+ mTorchUidMap[id].second = uid;
+ } else {
+ // Set the pending UID
+ mTorchUidMap[id].first = uid;
+ }
+}
+
Status CameraService::notifySystemEvent(int32_t eventId,
const std::vector<int32_t>& args) {
const int pid = CameraThreadState::getCallingPid();
@@ -2166,6 +2333,13 @@
doUserSwitch(/*newUserIds*/ args);
break;
}
+ case ICameraService::EVENT_USB_DEVICE_ATTACHED:
+ case ICameraService::EVENT_USB_DEVICE_DETACHED: {
+ // Notify CameraProviderManager for lazy HALs
+ mCameraProviderManager->notifyUsbDeviceEvent(eventId,
+ std::to_string(args[0]));
+ break;
+ }
case ICameraService::EVENT_NONE:
default: {
ALOGW("%s: Received invalid system event from system_server: %d", __FUNCTION__,
@@ -2208,23 +2382,7 @@
ATRACE_CALL();
- using hardware::camera::provider::V2_5::DeviceState;
- hardware::hidl_bitfield<DeviceState> newDeviceState{};
- if (newState & ICameraService::DEVICE_STATE_BACK_COVERED) {
- newDeviceState |= DeviceState::BACK_COVERED;
- }
- if (newState & ICameraService::DEVICE_STATE_FRONT_COVERED) {
- newDeviceState |= DeviceState::FRONT_COVERED;
- }
- if (newState & ICameraService::DEVICE_STATE_FOLDED) {
- newDeviceState |= DeviceState::FOLDED;
- }
- // Only map vendor bits directly
- uint64_t vendorBits = static_cast<uint64_t>(newState) & 0xFFFFFFFF00000000l;
- newDeviceState |= vendorBits;
-
- ALOGV("%s: New device state 0x%" PRIx64, __FUNCTION__, newDeviceState);
- mCameraProviderManager->notifyDeviceStateChange(newDeviceState);
+ mCameraProviderManager->notifyDeviceStateChange(newState);
return Status::ok();
}
@@ -2258,9 +2416,11 @@
if (current != nullptr) {
const auto basicClient = current->getValue();
if (basicClient.get() != nullptr && basicClient->canCastToApiClient(API_2)) {
- basicClient->setRotateAndCropOverride(
- CameraServiceProxyWrapper::getRotateAndCropOverride(
- basicClient->getPackageName(), basicClient->getCameraFacing()));
+ basicClient->setRotateAndCropOverride(
+ CameraServiceProxyWrapper::getRotateAndCropOverride(
+ basicClient->getPackageName(),
+ basicClient->getCameraFacing(),
+ multiuser_get_user_id(basicClient->getClientUid())));
}
}
}
@@ -3759,9 +3919,10 @@
// ----------------------------------------------------------------------------
CameraService::CameraState::CameraState(const String8& id, int cost,
- const std::set<String8>& conflicting, SystemCameraKind systemCameraKind) : mId(id),
+ const std::set<String8>& conflicting, SystemCameraKind systemCameraKind,
+ const std::vector<std::string>& physicalCameras) : mId(id),
mStatus(StatusInternal::NOT_PRESENT), mCost(cost), mConflicting(conflicting),
- mSystemCameraKind(systemCameraKind) {}
+ mSystemCameraKind(systemCameraKind), mPhysicalCameras(physicalCameras) {}
CameraService::CameraState::~CameraState() {}
@@ -3800,6 +3961,11 @@
return mSystemCameraKind;
}
+bool CameraService::CameraState::containsPhysicalCamera(const std::string& physicalCameraId) const {
+ return std::find(mPhysicalCameras.begin(), mPhysicalCameras.end(), physicalCameraId)
+ != mPhysicalCameras.end();
+}
+
bool CameraService::CameraState::addUnavailablePhysicalId(const String8& physicalId) {
Mutex::Autolock lock(mStatusLock);
auto result = mUnavailablePhysicalIds.insert(physicalId);
@@ -4284,12 +4450,20 @@
if (dumpVector.empty()) { return; }
+ std::string dumpString;
+
+ String8 currentTime = getFormattedCurrentTime();
+ dumpString += "Cached @ ";
+ dumpString += currentTime.string();
+ dumpString += "\n"; // First line is the timestamp of when client is cached.
+
+
const String16 &packageName = client->getPackageName();
String8 packageName8 = String8(packageName);
const char *printablePackageName = packageName8.lockBuffer(packageName.size());
- std::string dumpString;
+
size_t i = dumpVector.size();
// Store the string in reverse order (latest last)
@@ -4524,18 +4698,9 @@
std::list<String16> retList;
Mutex::Autolock lock(mCameraStatesLock);
for (const auto& state : mCameraStates) {
- std::vector<std::string> physicalCameraIds;
- if (!mCameraProviderManager->isLogicalCamera(state.first.c_str(), &physicalCameraIds)) {
- // This is not a logical multi-camera.
- continue;
+ if (state.second->containsPhysicalCamera(physicalCameraId.c_str())) {
+ retList.emplace_back(String16(state.first));
}
- if (std::find(physicalCameraIds.begin(), physicalCameraIds.end(), physicalCameraId.c_str())
- == physicalCameraIds.end()) {
- // cameraId is not a physical camera of this logical multi-camera.
- continue;
- }
-
- retList.emplace_back(String16(state.first));
}
return retList;
}
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 51c734f..c73d28a 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -106,19 +106,19 @@
// HAL Callbacks - implements CameraProviderManager::StatusListener
virtual void onDeviceStatusChanged(const String8 &cameraId,
- hardware::camera::common::V1_0::CameraDeviceStatus newHalStatus) override;
+ CameraDeviceStatus newHalStatus) override;
virtual void onDeviceStatusChanged(const String8 &cameraId,
const String8 &physicalCameraId,
- hardware::camera::common::V1_0::CameraDeviceStatus newHalStatus) override;
+ CameraDeviceStatus newHalStatus) override;
// This method may hold CameraProviderManager::mInterfaceMutex as a part
// of calling getSystemCameraKind() internally. Care should be taken not to
// directly / indirectly call this from callers who also hold
// mInterfaceMutex.
virtual void onTorchStatusChanged(const String8& cameraId,
- hardware::camera::common::V1_0::TorchModeStatus newStatus) override;
+ TorchModeStatus newStatus) override;
// Does not hold CameraProviderManager::mInterfaceMutex.
virtual void onTorchStatusChanged(const String8& cameraId,
- hardware::camera::common::V1_0::TorchModeStatus newStatus,
+ TorchModeStatus newStatus,
SystemCameraKind kind) override;
virtual void onNewProviderRegistered() override;
@@ -172,6 +172,12 @@
virtual binder::Status setTorchMode(const String16& cameraId, bool enabled,
const sp<IBinder>& clientBinder);
+ virtual binder::Status turnOnTorchWithStrengthLevel(const String16& cameraId,
+ int32_t torchStrength, const sp<IBinder>& clientBinder);
+
+ virtual binder::Status getTorchStrengthLevel(const String16& cameraId,
+ int32_t* torchStrength);
+
virtual binder::Status notifySystemEvent(int32_t eventId,
const std::vector<int32_t>& args);
@@ -552,8 +558,6 @@
private:
- typedef hardware::camera::common::V1_0::CameraDeviceStatus CameraDeviceStatus;
-
/**
* Typesafe version of device status, containing both the HAL-layer and the service interface-
* layer values.
@@ -583,7 +587,7 @@
* returned in the HAL's camera_info struct for each device.
*/
CameraState(const String8& id, int cost, const std::set<String8>& conflicting,
- SystemCameraKind deviceKind);
+ SystemCameraKind deviceKind, const std::vector<std::string>& physicalCameras);
virtual ~CameraState();
/**
@@ -641,6 +645,12 @@
SystemCameraKind getSystemCameraKind() const;
/**
+ * Return whether this camera is a logical multi-camera and has a
+ * particular physical sub-camera.
+ */
+ bool containsPhysicalCamera(const std::string& physicalCameraId) const;
+
+ /**
* Add/Remove the unavailable physical camera ID.
*/
bool addUnavailablePhysicalId(const String8& physicalId);
@@ -668,6 +678,7 @@
mutable Mutex mStatusLock;
CameraParameters mShimParams;
const SystemCameraKind mSystemCameraKind;
+ const std::vector<std::string> mPhysicalCameras; // Empty if not a logical multi-camera
}; // class CameraState
// Observer for UID lifecycle enforcing that UIDs in idle
@@ -1089,7 +1100,7 @@
// guard mTorchUidMap
Mutex mTorchUidMapMutex;
// camera id -> torch status
- KeyedVector<String8, hardware::camera::common::V1_0::TorchModeStatus>
+ KeyedVector<String8, TorchModeStatus>
mTorchStatusMap;
// camera id -> torch client binder
// only store the last client that turns on each camera's torch mode
@@ -1103,16 +1114,16 @@
// handle torch mode status change and invoke callbacks. mTorchStatusMutex
// should be locked.
void onTorchStatusChangedLocked(const String8& cameraId,
- hardware::camera::common::V1_0::TorchModeStatus newStatus,
+ TorchModeStatus newStatus,
SystemCameraKind systemCameraKind);
// get a camera's torch status. mTorchStatusMutex should be locked.
status_t getTorchStatusLocked(const String8 &cameraId,
- hardware::camera::common::V1_0::TorchModeStatus *status) const;
+ TorchModeStatus *status) const;
// set a camera's torch status. mTorchStatusMutex should be locked.
status_t setTorchStatusLocked(const String8 &cameraId,
- hardware::camera::common::V1_0::TorchModeStatus status);
+ TorchModeStatus status);
// notify physical camera status when the physical camera is public.
// Expects mStatusListenerLock to be locked.
@@ -1223,14 +1234,15 @@
status_t checkCameraAccess(const String16& opPackageName);
static String8 toString(std::set<userid_t> intSet);
- static int32_t mapToInterface(hardware::camera::common::V1_0::TorchModeStatus status);
- static StatusInternal mapToInternal(hardware::camera::common::V1_0::CameraDeviceStatus status);
+ static int32_t mapToInterface(TorchModeStatus status);
+ static StatusInternal mapToInternal(CameraDeviceStatus status);
static int32_t mapToInterface(StatusInternal status);
void broadcastTorchModeStatus(const String8& cameraId,
- hardware::camera::common::V1_0::TorchModeStatus status,
- SystemCameraKind systemCameraKind);
+ TorchModeStatus status, SystemCameraKind systemCameraKind);
+
+ void broadcastTorchStrengthLevel(const String8& cameraId, int32_t newTorchStrengthLevel);
void disconnectClient(const String8& id, sp<BasicClient> clientToDisconnect);
@@ -1310,6 +1322,8 @@
bool mInjectionInitPending = false;
// Guard mInjectionInternalCamId and mInjectionInitPending.
Mutex mInjectionParametersLock;
+
+ void updateTorchUidMapLocked(const String16& cameraId, int uid);
};
} // namespace android
diff --git a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
index eed2654..a38d7ae 100755
--- a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
@@ -78,7 +78,8 @@
}
// Find out buffer size for JPEG
- ssize_t maxJpegSize = device->getJpegBufferSize(params.pictureWidth, params.pictureHeight);
+ ssize_t maxJpegSize = device->getJpegBufferSize(device->infoPhysical(String8("")),
+ params.pictureWidth, params.pictureHeight);
if (maxJpegSize <= 0) {
ALOGE("%s: Camera %d: Jpeg buffer size (%zu) is invalid ",
__FUNCTION__, mId, maxJpegSize);
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index a406e62..9a7ada2 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -75,23 +75,43 @@
// Treat the H.264 max size as the max supported video size.
MediaProfiles *videoEncoderProfiles = MediaProfiles::getInstance();
Vector<video_encoder> encoders = videoEncoderProfiles->getVideoEncoders();
+ int32_t minVideoWidth = MAX_PREVIEW_WIDTH;
+ int32_t minVideoHeight = MAX_PREVIEW_HEIGHT;
int32_t maxVideoWidth = 0;
int32_t maxVideoHeight = 0;
for (size_t i = 0; i < encoders.size(); i++) {
- int width = videoEncoderProfiles->getVideoEncoderParamByName(
+ int w0 = videoEncoderProfiles->getVideoEncoderParamByName(
+ "enc.vid.width.min", encoders[i]);
+ int h0 = videoEncoderProfiles->getVideoEncoderParamByName(
+ "enc.vid.height.min", encoders[i]);
+ int w1 = videoEncoderProfiles->getVideoEncoderParamByName(
"enc.vid.width.max", encoders[i]);
- int height = videoEncoderProfiles->getVideoEncoderParamByName(
+ int h1 = videoEncoderProfiles->getVideoEncoderParamByName(
"enc.vid.height.max", encoders[i]);
- // Treat width/height separately here to handle the case where different
- // profile might report max size of different aspect ratio
- if (width > maxVideoWidth) {
- maxVideoWidth = width;
+ // Assume the min size is 0 if it's not reported by encoder
+ if (w0 == -1) {
+ w0 = 0;
}
- if (height > maxVideoHeight) {
- maxVideoHeight = height;
+ if (h0 == -1) {
+ h0 = 0;
+ }
+ // Treat width/height separately here to handle the case where different
+ // profile might report min/max size of different aspect ratio
+ if (w0 < minVideoWidth) {
+ minVideoWidth = w0;
+ }
+ if (h0 < minVideoHeight) {
+ minVideoHeight = h0;
+ }
+ if (w1 > maxVideoWidth) {
+ maxVideoWidth = w1;
+ }
+ if (h1 > maxVideoHeight) {
+ maxVideoHeight = h1;
}
}
- // This is just an upper bound and may not be an actually valid video size
+ // These are upper/lower bounds and may not be an actually valid video size
+ const Size VIDEO_SIZE_LOWER_BOUND = {minVideoWidth, minVideoHeight};
Size videoSizeUpperBound = {maxVideoWidth, maxVideoHeight};
if (fastInfo.supportsPreferredConfigs) {
@@ -99,9 +119,10 @@
videoSizeUpperBound = getMaxSize(getPreferredVideoSizes());
}
- res = getFilteredSizes(maxPreviewSize, &availablePreviewSizes);
+ res = getFilteredSizes(Size{0, 0}, maxPreviewSize, &availablePreviewSizes);
if (res != OK) return res;
- res = getFilteredSizes(videoSizeUpperBound, &availableVideoSizes);
+ res = getFilteredSizes(
+ VIDEO_SIZE_LOWER_BOUND, videoSizeUpperBound, &availableVideoSizes);
if (res != OK) return res;
// Select initial preview and video size that's under the initial bound and
@@ -1055,7 +1076,8 @@
if (fastInfo.supportsPreferredConfigs) {
previewSizeBound = getMaxSize(getPreferredPreviewSizes());
}
- status_t res = getFilteredSizes(previewSizeBound, &supportedPreviewSizes);
+ status_t res = getFilteredSizes(
+ Size{0, 0}, previewSizeBound, &supportedPreviewSizes);
if (res != OK) return res;
for (size_t i=0; i < availableFpsRanges.count; i += 2) {
if (!isFpsSupported(supportedPreviewSizes,
@@ -2998,7 +3020,8 @@
}
}
-status_t Parameters::getFilteredSizes(Size limit, Vector<Size> *sizes) {
+status_t Parameters::getFilteredSizes(const Size &lower, const Size &upper,
+ Vector<Size> *sizes) {
if (info == NULL) {
ALOGE("%s: Static metadata is not initialized", __FUNCTION__);
return NO_INIT;
@@ -3014,7 +3037,8 @@
const StreamConfiguration &sc = scs[i];
if (sc.isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
sc.format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED &&
- ((sc.width * sc.height) <= (limit.width * limit.height))) {
+ ((sc.width * sc.height) >= (lower.width * lower.height)) &&
+ ((sc.width * sc.height) <= (upper.width * upper.height))) {
int64_t minFrameDuration = getMinFrameDurationNs(
{sc.width, sc.height}, HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED);
if (minFrameDuration > MAX_PREVIEW_RECORD_DURATION_NS) {
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.h b/services/camera/libcameraservice/api1/client2/Parameters.h
index 1b2ceda..263025e 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.h
+++ b/services/camera/libcameraservice/api1/client2/Parameters.h
@@ -396,9 +396,10 @@
Vector<Size> availablePreviewSizes;
Vector<Size> availableVideoSizes;
- // Get size list (that are no larger than limit) from static metadata.
+ // Get size list (that fall within lower/upper bounds) from static metadata.
// This method filtered size with minFrameDuration < MAX_PREVIEW_RECORD_DURATION_NS
- status_t getFilteredSizes(Size limit, Vector<Size> *sizes);
+ status_t getFilteredSizes(const Size &lower, const Size &upper,
+ Vector<Size> *sizes);
// Get max size (from the size array) that matches the given aspect ratio.
Size getMaxSizeForRatio(float ratio, const int32_t* sizeArray, size_t count);
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 1c26081..f33ae97 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -51,8 +51,8 @@
namespace android {
using namespace camera2;
+using namespace camera3;
using camera3::camera_stream_rotation_t::CAMERA_STREAM_ROTATION_0;
-using camera3::SessionConfigurationUtils;
CameraDeviceClientBase::CameraDeviceClientBase(
const sp<CameraService>& cameraService,
@@ -140,6 +140,40 @@
physicalKeysEntry.data.i32 + physicalKeysEntry.count);
}
+ auto entry = deviceInfo.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
+ mDynamicProfileMap.emplace(
+ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD,
+ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD);
+ if (entry.count > 0) {
+ const auto it = std::find(entry.data.i32, entry.data.i32 + entry.count,
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT);
+ if (it != entry.data.i32 + entry.count) {
+ entry = deviceInfo.find(ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP);
+ if (entry.count > 0 || ((entry.count % 2) != 0)) {
+ int standardBitmap = ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD;
+ for (size_t i = 0; i < entry.count; i += 2) {
+ if (entry.data.i32[i] !=
+ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD) {
+ mDynamicProfileMap.emplace(entry.data.i32[i], entry.data.i32[i+1]);
+ if ((entry.data.i32[i+1] == 0) || (entry.data.i32[i+1] &
+ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD)) {
+ standardBitmap |= entry.data.i32[i];
+ }
+ } else {
+ ALOGE("%s: Device %s includes unexpected profile entry: 0x%x!",
+ __FUNCTION__, mCameraIdStr.c_str(), entry.data.i32[i]);
+ }
+ }
+ mDynamicProfileMap.emplace(
+ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD,
+ standardBitmap);
+ } else {
+ ALOGE("%s: Device %s supports 10-bit output but doesn't include a dynamic range"
+ " profile map!", __FUNCTION__, mCameraIdStr.c_str());
+ }
+ }
+ }
+
mProviderManager = providerPtr;
// Cache physical camera ids corresponding to this device and also the high
// resolution sensors in this device + physical camera ids
@@ -297,6 +331,7 @@
SurfaceMap surfaceMap;
Vector<int32_t> outputStreamIds;
std::vector<std::string> requestedPhysicalIds;
+ int dynamicProfileBitmap = 0;
if (request.mSurfaceList.size() > 0) {
for (const sp<Surface>& surface : request.mSurfaceList) {
if (surface == 0) continue;
@@ -313,6 +348,8 @@
String8 requestedPhysicalId(
mConfiguredOutputs.valueAt(index).getPhysicalCameraId());
requestedPhysicalIds.push_back(requestedPhysicalId.string());
+ dynamicProfileBitmap |=
+ mConfiguredOutputs.valueAt(index).getDynamicRangeProfile();
} else {
ALOGW("%s: Output stream Id not found among configured outputs!", __FUNCTION__);
}
@@ -348,6 +385,41 @@
String8 requestedPhysicalId(
mConfiguredOutputs.valueAt(index).getPhysicalCameraId());
requestedPhysicalIds.push_back(requestedPhysicalId.string());
+ dynamicProfileBitmap |=
+ mConfiguredOutputs.valueAt(index).getDynamicRangeProfile();
+ }
+ }
+
+ if (dynamicProfileBitmap !=
+ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD) {
+ for (int i = ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD;
+ i < ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_MAX; i <<= 1) {
+ if ((dynamicProfileBitmap & i) == 0) {
+ continue;
+ }
+
+ const auto& it = mDynamicProfileMap.find(i);
+ if (it != mDynamicProfileMap.end()) {
+ if ((it->second == 0) ||
+ ((it->second & dynamicProfileBitmap) == dynamicProfileBitmap)) {
+ continue;
+ } else {
+ ALOGE("%s: Camera %s: Tried to submit a request with a surfaces that"
+ " reference an unsupported dynamic range profile combination"
+ " 0x%x!", __FUNCTION__, mCameraIdStr.string(),
+ dynamicProfileBitmap);
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
+ "Request targets an unsupported dynamic range profile"
+ " combination");
+ }
+ } else {
+ ALOGE("%s: Camera %s: Tried to submit a request with a surface that"
+ " references unsupported dynamic range profile 0x%x!",
+ __FUNCTION__, mCameraIdStr.string(), i);
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
+ "Request targets 10-bit Surface with unsupported dynamic range"
+ " profile");
+ }
}
}
@@ -638,27 +710,9 @@
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
}
- hardware::camera::device::V3_7::StreamConfiguration streamConfiguration;
- bool earlyExit = false;
- camera3::metadataGetter getMetadata = [this](const String8 &id, bool /*overrideForPerfClass*/) {
- return mDevice->infoPhysical(id);};
- std::vector<std::string> physicalCameraIds;
- mProviderManager->isLogicalCamera(mCameraIdStr.string(), &physicalCameraIds);
- res = SessionConfigurationUtils::convertToHALStreamCombination(sessionConfiguration,
- mCameraIdStr, mDevice->info(), getMetadata, physicalCameraIds, streamConfiguration,
- mOverrideForPerfClass, &earlyExit);
- if (!res.isOk()) {
- return res;
- }
-
- if (earlyExit) {
- *status = false;
- return binder::Status::ok();
- }
-
*status = false;
ret = mProviderManager->isSessionConfigurationSupported(mCameraIdStr.string(),
- streamConfiguration, status);
+ sessionConfiguration, mOverrideForPerfClass, status);
switch (ret) {
case OK:
// Expected, do nothing.
@@ -801,6 +855,7 @@
String8 physicalCameraId = String8(outputConfiguration.getPhysicalCameraId());
bool deferredConsumerOnly = deferredConsumer && numBufferProducers == 0;
bool isMultiResolution = outputConfiguration.isMultiResolution();
+ int dynamicRangeProfile = outputConfiguration.getDynamicRangeProfile();
res = SessionConfigurationUtils::checkSurfaceType(numBufferProducers, deferredConsumer,
outputConfiguration.getSurfaceType());
@@ -844,7 +899,7 @@
sp<Surface> surface;
res = SessionConfigurationUtils::createSurfaceFromGbp(streamInfo,
isStreamInfoValid, surface, bufferProducer, mCameraIdStr,
- mDevice->infoPhysical(physicalCameraId), sensorPixelModesUsed);
+ mDevice->infoPhysical(physicalCameraId), sensorPixelModesUsed, dynamicRangeProfile);
if (!res.isOk())
return res;
@@ -888,7 +943,8 @@
streamInfo.height, streamInfo.format, streamInfo.dataSpace,
static_cast<camera_stream_rotation_t>(outputConfiguration.getRotation()),
&streamId, physicalCameraId, streamInfo.sensorPixelModesUsed, &surfaceIds,
- outputConfiguration.getSurfaceSetID(), isShared, isMultiResolution);
+ outputConfiguration.getSurfaceSetID(), isShared, isMultiResolution,
+ streamInfo.dynamicRangeProfile);
}
if (err != OK) {
@@ -982,7 +1038,8 @@
overriddenSensorPixelModesUsed,
&surfaceIds,
outputConfiguration.getSurfaceSetID(), isShared,
- outputConfiguration.isMultiResolution(), consumerUsage);
+ outputConfiguration.isMultiResolution(), consumerUsage,
+ outputConfiguration.getDynamicRangeProfile());
if (err != OK) {
res = STATUS_ERROR_FMT(CameraService::ERROR_INVALID_OPERATION,
@@ -995,7 +1052,8 @@
mDeferredStreams.push_back(streamId);
mStreamInfoMap.emplace(std::piecewise_construct, std::forward_as_tuple(streamId),
std::forward_as_tuple(width, height, format, dataSpace, consumerUsage,
- overriddenSensorPixelModesUsed));
+ overriddenSensorPixelModesUsed,
+ outputConfiguration.getDynamicRangeProfile()));
ALOGV("%s: Camera %s: Successfully created a new stream ID %d for a deferred surface"
" (%d x %d) stream with format 0x%x.",
@@ -1184,12 +1242,14 @@
const std::vector<int32_t> &sensorPixelModesUsed =
outputConfiguration.getSensorPixelModesUsed();
+ int dynamicRangeProfile = outputConfiguration.getDynamicRangeProfile();
+
for (size_t i = 0; i < newOutputsMap.size(); i++) {
OutputStreamInfo outInfo;
sp<Surface> surface;
res = SessionConfigurationUtils::createSurfaceFromGbp(outInfo,
/*isStreamInfoValid*/ false, surface, newOutputsMap.valueAt(i), mCameraIdStr,
- mDevice->infoPhysical(physicalCameraId), sensorPixelModesUsed);
+ mDevice->infoPhysical(physicalCameraId), sensorPixelModesUsed, dynamicRangeProfile);
if (!res.isOk())
return res;
@@ -1546,6 +1606,7 @@
std::vector<sp<Surface>> consumerSurfaces;
const std::vector<int32_t> &sensorPixelModesUsed =
outputConfiguration.getSensorPixelModesUsed();
+ int dynamicRangeProfile = outputConfiguration.getDynamicRangeProfile();
for (auto& bufferProducer : bufferProducers) {
// Don't create multiple streams for the same target surface
ssize_t index = mStreamMap.indexOfKey(IInterface::asBinder(bufferProducer));
@@ -1558,7 +1619,7 @@
sp<Surface> surface;
res = SessionConfigurationUtils::createSurfaceFromGbp(mStreamInfoMap[streamId],
true /*isStreamInfoValid*/, surface, bufferProducer, mCameraIdStr,
- mDevice->infoPhysical(physicalId), sensorPixelModesUsed);
+ mDevice->infoPhysical(physicalId), sensorPixelModesUsed, dynamicRangeProfile);
if (!res.isOk())
return res;
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index 288f2d7..77cdf9c 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -22,6 +22,7 @@
#include <camera/camera2/OutputConfiguration.h>
#include <camera/camera2/SessionConfiguration.h>
#include <camera/camera2/SubmitInfo.h>
+#include <unordered_map>
#include "CameraOfflineSessionClient.h"
#include "CameraService.h"
@@ -303,6 +304,10 @@
// Stream ID -> OutputConfiguration. Used for looking up Surface by stream/surface index
KeyedVector<int32_t, hardware::camera2::params::OutputConfiguration> mConfiguredOutputs;
+ // Dynamic range profile id -> Supported dynamic profiles bitmap within an single capture
+ // request
+ std::unordered_map<int, int> mDynamicProfileMap;
+
struct InputStreamConfiguration {
bool configured;
int32_t width;
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index 5d17c11..55c7579 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -34,6 +34,7 @@
#include "api2/CameraDeviceClient.h"
#include "device3/Camera3Device.h"
+#include "device3/hidl/HidlCamera3Device.h"
#include "utils/CameraThreadState.h"
#include "utils/CameraServiceProxyWrapper.h"
@@ -62,14 +63,14 @@
servicePid),
mSharedCameraCallbacks(remoteCallback),
mDeviceVersion(cameraService->getDeviceVersion(TClientBase::mCameraIdStr)),
- mDevice(new Camera3Device(cameraId, overrideForPerfClass, legacyClient)),
mDeviceActive(false), mApi1CameraId(api1CameraId)
{
ALOGI("Camera %s: Opened. Client: %s (PID %d, UID %d)", cameraId.string(),
String8(clientPackageName).string(), clientPid, clientUid);
mInitialClientPid = clientPid;
- LOG_ALWAYS_FATAL_IF(mDevice == 0, "Device should never be NULL here.");
+ mOverrideForPerfClass = overrideForPerfClass;
+ mLegacyClient = legacyClient;
}
template <typename TClientBase>
@@ -104,7 +105,26 @@
if (res != OK) {
return res;
}
-
+ IPCTransport providerTransport = IPCTransport::INVALID;
+ res = providerPtr->getCameraIdIPCTransport(TClientBase::mCameraIdStr.string(),
+ &providerTransport);
+ if (res != OK) {
+ return res;
+ }
+ switch (providerTransport) {
+ case IPCTransport::HIDL:
+ mDevice =
+ new HidlCamera3Device(TClientBase::mCameraIdStr, mOverrideForPerfClass,
+ mLegacyClient);
+ break;
+ case IPCTransport::AIDL:
+ ALOGE("%s: AIDL camera3Devices not available yet", __FUNCTION__);
+ return NO_INIT;
+ default:
+ ALOGE("%s Invalid transport for camera id %s", __FUNCTION__,
+ TClientBase::mCameraIdStr.string());
+ return NO_INIT;
+ }
if (mDevice == NULL) {
ALOGE("%s: Camera %s: No device connected",
__FUNCTION__, TClientBase::mCameraIdStr.string());
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.h b/services/camera/libcameraservice/common/Camera2ClientBase.h
index 4688502..296ef43 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.h
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.h
@@ -126,6 +126,8 @@
// The PID provided in the constructor call
pid_t mInitialClientPid;
+ bool mOverrideForPerfClass = false;
+ bool mLegacyClient = false;
virtual sp<IBinder> asBinderWrapper() {
return IInterface::asBinder(this);
@@ -145,9 +147,12 @@
const int mDeviceVersion;
- // Set to const to avoid mDevice being updated (update of sp<> is racy) during
- // dumpDevice (which is important to be lock free for debugging purpose)
- const sp<CameraDeviceBase> mDevice;
+ // Note: This was previously set to const to avoid mDevice being updated -
+ // b/112639939 (update of sp<> is racy) during dumpDevice (which is important to be lock free
+ // for debugging purpose). The const has been removed since CameraDeviceBase
+ // needs to be set during initializeImpl(). This must not be set / cleared
+ // anywhere else.
+ sp<CameraDeviceBase> mDevice;
/** Utility members */
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index 06a3d36..e936cb6 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -102,7 +102,8 @@
virtual status_t dumpWatchedEventsToVector(std::vector<std::string> &out) = 0;
/**
- * The physical camera device's static characteristics metadata buffer
+ * The physical camera device's static characteristics metadata buffer, or
+ * the logical camera's static characteristics if physical id is empty.
*/
virtual const CameraMetadata& infoPhysical(const String8& physicalId) const = 0;
@@ -181,7 +182,8 @@
std::vector<int> *surfaceIds = nullptr,
int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID,
bool isShared = false, bool isMultiResolution = false,
- uint64_t consumerUsage = 0) = 0;
+ uint64_t consumerUsage = 0,
+ int dynamicProfile = ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD) = 0;
/**
* Create an output stream of the requested size, format, rotation and
@@ -198,7 +200,8 @@
std::vector<int> *surfaceIds = nullptr,
int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID,
bool isShared = false, bool isMultiResolution = false,
- uint64_t consumerUsage = 0) = 0;
+ uint64_t consumerUsage = 0,
+ int dynamicProfile = ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD) = 0;
/**
* Create an input stream of width, height, and format.
@@ -219,10 +222,12 @@
android_dataspace dataSpace;
bool dataSpaceOverridden;
android_dataspace originalDataSpace;
+ uint32_t dynamicRangeProfile;
StreamInfo() : width(0), height(0), format(0), formatOverridden(false), originalFormat(0),
dataSpace(HAL_DATASPACE_UNKNOWN), dataSpaceOverridden(false),
- originalDataSpace(HAL_DATASPACE_UNKNOWN) {}
+ originalDataSpace(HAL_DATASPACE_UNKNOWN),
+ dynamicRangeProfile(ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD){}
/**
* Check whether the format matches the current or the original one in case
* it got overridden.
@@ -307,7 +312,8 @@
* Get Jpeg buffer size for a given jpeg resolution.
* Negative values are error codes.
*/
- virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const = 0;
+ virtual ssize_t getJpegBufferSize(const CameraMetadata &info, uint32_t width,
+ uint32_t height) const = 0;
/**
* Connect HAL notifications to a listener. Overwrites previous
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index 0cce2ca..4227d28 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -20,11 +20,12 @@
#include "CameraProviderManager.h"
-#include <android/hardware/camera/device/3.7/ICameraDevice.h>
+#include <android/hardware/camera/device/3.8/ICameraDevice.h>
#include <algorithm>
#include <chrono>
#include "common/DepthPhotoProcessor.h"
+#include "hidl/HidlProviderInfo.h"
#include <dlfcn.h>
#include <future>
#include <inttypes.h>
@@ -45,26 +46,27 @@
namespace android {
using namespace ::android::hardware::camera;
-using namespace ::android::hardware::camera::common::V1_0;
-using camera3::SessionConfigurationUtils;
+using namespace ::android::camera3;
+using android::hardware::camera::common::V1_0::Status;
+using namespace camera3::SessionConfigurationUtils;
using std::literals::chrono_literals::operator""s;
using hardware::camera2::utils::CameraIdAndSessionConfiguration;
-using hardware::camera::provider::V2_7::CameraIdAndStreamCombination;
namespace {
const bool kEnableLazyHal(property_get_bool("ro.camera.enableLazyHal", false));
+const std::string kExternalProviderName = "external/0";
} // anonymous namespace
const float CameraProviderManager::kDepthARTolerance = .1f;
-CameraProviderManager::HardwareServiceInteractionProxy
-CameraProviderManager::sHardwareServiceInteractionProxy{};
+CameraProviderManager::HidlServiceInteractionProxyImpl
+CameraProviderManager::sHidlServiceInteractionProxy{};
CameraProviderManager::~CameraProviderManager() {
}
hardware::hidl_vec<hardware::hidl_string>
-CameraProviderManager::HardwareServiceInteractionProxy::listServices() {
+CameraProviderManager::HidlServiceInteractionProxyImpl::listServices() {
hardware::hidl_vec<hardware::hidl_string> ret;
auto manager = hardware::defaultServiceManager1_2();
if (manager != nullptr) {
@@ -77,19 +79,18 @@
}
status_t CameraProviderManager::initialize(wp<CameraProviderManager::StatusListener> listener,
- ServiceInteractionProxy* proxy) {
+ HidlServiceInteractionProxy* hidlProxy) {
std::lock_guard<std::mutex> lock(mInterfaceMutex);
- if (proxy == nullptr) {
+ if (hidlProxy == nullptr) {
ALOGE("%s: No valid service interaction proxy provided", __FUNCTION__);
return BAD_VALUE;
}
mListener = listener;
- mServiceProxy = proxy;
- mDeviceState = static_cast<hardware::hidl_bitfield<provider::V2_5::DeviceState>>(
- provider::V2_5::DeviceState::NORMAL);
+ mHidlServiceProxy = hidlProxy;
+ mDeviceState = 0;
// Registering will trigger notifications for all already-known providers
- bool success = mServiceProxy->registerForNotifications(
+ bool success = mHidlServiceProxy->registerForNotifications(
/* instance name, empty means no filter */ "",
this);
if (!success) {
@@ -98,9 +99,8 @@
return INVALID_OPERATION;
}
-
- for (const auto& instance : mServiceProxy->listServices()) {
- this->addProviderLocked(instance);
+ for (const auto& instance : mHidlServiceProxy->listServices()) {
+ this->addHidlProviderLocked(instance);
}
IPCThreadState::self()->flushCommands();
@@ -267,7 +267,7 @@
}
status_t CameraProviderManager::isSessionConfigurationSupported(const std::string& id,
- const hardware::camera::device::V3_7::StreamConfiguration &configuration,
+ const SessionConfiguration &configuration, bool overrideForPerfClass,
bool *status /*out*/) const {
std::lock_guard<std::mutex> lock(mInterfaceMutex);
auto deviceInfo = findDeviceInfoLocked(id);
@@ -275,7 +275,22 @@
return NAME_NOT_FOUND;
}
- return deviceInfo->isSessionConfigurationSupported(configuration, status);
+ return deviceInfo->isSessionConfigurationSupported(configuration, overrideForPerfClass, status);
+}
+
+status_t CameraProviderManager::getCameraIdIPCTransport(const std::string &id,
+ IPCTransport *providerTransport) const {
+ std::lock_guard<std::mutex> lock(mInterfaceMutex);
+ auto deviceInfo = findDeviceInfoLocked(id);
+ if (deviceInfo == nullptr) {
+ return NAME_NOT_FOUND;
+ }
+ sp<ProviderInfo> parentProvider = deviceInfo->mParentProvider.promote();
+ if (parentProvider == nullptr) {
+ return DEAD_OBJECT;
+ }
+ *providerTransport = parentProvider->getIPCTransport();
+ return OK;
}
status_t CameraProviderManager::getCameraCharacteristics(const std::string &id,
@@ -284,6 +299,9 @@
return getCameraCharacteristicsLocked(id, overrideForPerfClass, characteristics);
}
+// Till hidl is removed from the android source tree, we use this for aidl as
+// well. We artificially give aidl camera device version 1 a major version 3 and minor
+// version 8.
status_t CameraProviderManager::getHighestSupportedVersion(const std::string &id,
hardware::hidl_version *v) {
std::lock_guard<std::mutex> lock(mInterfaceMutex);
@@ -307,6 +325,50 @@
return OK;
}
+status_t CameraProviderManager::getTorchStrengthLevel(const std::string &id,
+ int32_t* torchStrength /*out*/) {
+ std::lock_guard<std::mutex> lock(mInterfaceMutex);
+
+ auto deviceInfo = findDeviceInfoLocked(id);
+ if (deviceInfo == nullptr) return NAME_NOT_FOUND;
+
+ return deviceInfo->getTorchStrengthLevel(torchStrength);
+}
+
+status_t CameraProviderManager::turnOnTorchWithStrengthLevel(const std::string &id,
+ int32_t torchStrength) {
+ std::lock_guard<std::mutex> lock(mInterfaceMutex);
+
+ auto deviceInfo = findDeviceInfoLocked(id);
+ if (deviceInfo == nullptr) return NAME_NOT_FOUND;
+
+ return deviceInfo->turnOnTorchWithStrengthLevel(torchStrength);
+}
+
+bool CameraProviderManager::shouldSkipTorchStrengthUpdate(const std::string &id,
+ int32_t torchStrength) const {
+ std::lock_guard<std::mutex> lock(mInterfaceMutex);
+
+ auto deviceInfo = findDeviceInfoLocked(id);
+ if (deviceInfo == nullptr) return NAME_NOT_FOUND;
+
+ if (deviceInfo->mTorchStrengthLevel == torchStrength) {
+ ALOGV("%s: Skipping torch strength level updates prev_level: %d, new_level: %d",
+ __FUNCTION__, deviceInfo->mTorchStrengthLevel, torchStrength);
+ return true;
+ }
+ return false;
+}
+
+int32_t CameraProviderManager::getTorchDefaultStrengthLevel(const std::string &id) const {
+ std::lock_guard<std::mutex> lock(mInterfaceMutex);
+
+ auto deviceInfo = findDeviceInfoLocked(id);
+ if (deviceInfo == nullptr) return NAME_NOT_FOUND;
+
+ return deviceInfo->mTorchDefaultStrengthLevel;
+}
+
bool CameraProviderManager::supportSetTorchMode(const std::string &id) const {
std::lock_guard<std::mutex> lock(mInterfaceMutex);
for (auto& provider : mProviders) {
@@ -330,11 +392,25 @@
if (parentProvider == nullptr) {
return DEAD_OBJECT;
}
- const sp<provider::V2_4::ICameraProvider> interface = parentProvider->startProviderInterface();
- if (interface == nullptr) {
- return DEAD_OBJECT;
+ std::shared_ptr<HalCameraProvider> halCameraProvider = nullptr;
+ IPCTransport providerTransport = parentProvider->getIPCTransport();
+ if (providerTransport == IPCTransport::HIDL) {
+ HidlProviderInfo * hidlProviderInfo = static_cast<HidlProviderInfo *>(parentProvider.get());
+ const sp<provider::V2_4::ICameraProvider> hidlInterface =
+ hidlProviderInfo->startProviderInterface();
+ if (hidlInterface == nullptr) {
+ return DEAD_OBJECT;
+ }
+ halCameraProvider =
+ std::make_shared<HidlHalCameraProvider>(hidlInterface, hidlInterface->descriptor);
+ } else if (providerTransport == IPCTransport::AIDL) {
+ ALOGE("%s AIDL hal providers not supported yet", __FUNCTION__);
+ return INVALID_OPERATION;
+ } else {
+ ALOGE("%s Invalid provider transport", __FUNCTION__);
+ return INVALID_OPERATION;
}
- saveRef(DeviceMode::TORCH, deviceInfo->mId, interface);
+ saveRef(DeviceMode::TORCH, deviceInfo->mId, halCameraProvider);
return deviceInfo->setTorchMode(enabled);
}
@@ -351,8 +427,72 @@
return OK;
}
-status_t CameraProviderManager::notifyDeviceStateChange(
- hardware::hidl_bitfield<provider::V2_5::DeviceState> newState) {
+sp<CameraProviderManager::ProviderInfo> CameraProviderManager::startExternalLazyProvider() const {
+ std::lock_guard<std::mutex> providerLock(mProviderLifecycleLock);
+ std::lock_guard<std::mutex> lock(mInterfaceMutex);
+
+ for (const auto& providerInfo : mProviders) {
+ if (providerInfo->isExternalLazyHAL()) {
+ if (!providerInfo->successfullyStartedProviderInterface()) {
+ return nullptr;
+ } else {
+ return providerInfo;
+ }
+ }
+ }
+ return nullptr;
+}
+
+status_t CameraProviderManager::notifyUsbDeviceEvent(int32_t eventId,
+ const std::string& usbDeviceId) {
+ if (!kEnableLazyHal) {
+ return OK;
+ }
+
+ ALOGV("notifySystemEvent: %d usbDeviceId : %s", eventId, usbDeviceId.c_str());
+
+ if (eventId == android::hardware::ICameraService::EVENT_USB_DEVICE_ATTACHED) {
+ sp<ProviderInfo> externalProvider = startExternalLazyProvider();
+ if (externalProvider != nullptr) {
+ auto usbDevices = mExternalUsbDevicesForProvider.first;
+ usbDevices.push_back(usbDeviceId);
+ mExternalUsbDevicesForProvider = {usbDevices, externalProvider};
+ }
+ } else if (eventId
+ == android::hardware::ICameraService::EVENT_USB_DEVICE_DETACHED) {
+ usbDeviceDetached(usbDeviceId);
+ }
+
+ return OK;
+}
+
+status_t CameraProviderManager::usbDeviceDetached(const std::string &usbDeviceId) {
+ std::lock_guard<std::mutex> providerLock(mProviderLifecycleLock);
+ std::lock_guard<std::mutex> interfaceLock(mInterfaceMutex);
+
+ auto usbDevices = mExternalUsbDevicesForProvider.first;
+ auto foundId = std::find(usbDevices.begin(), usbDevices.end(), usbDeviceId);
+ if (foundId != usbDevices.end()) {
+ sp<ProviderInfo> providerInfo = mExternalUsbDevicesForProvider.second;
+ if (providerInfo == nullptr) {
+ ALOGE("%s No valid external provider for USB device: %s",
+ __FUNCTION__,
+ usbDeviceId.c_str());
+ mExternalUsbDevicesForProvider = {std::vector<std::string>(), nullptr};
+ return DEAD_OBJECT;
+ } else {
+ mInterfaceMutex.unlock();
+ providerInfo->removeAllDevices();
+ mInterfaceMutex.lock();
+ mExternalUsbDevicesForProvider = {std::vector<std::string>(), nullptr};
+ }
+ } else {
+ return DEAD_OBJECT;
+ }
+ return OK;
+}
+
+status_t CameraProviderManager::notifyDeviceStateChange(int64_t newState) {
std::lock_guard<std::mutex> lock(mInterfaceMutex);
mDeviceState = newState;
status_t res = OK;
@@ -378,7 +518,7 @@
return res;
}
-status_t CameraProviderManager::openSession(const std::string &id,
+status_t CameraProviderManager::openHidlSession(const std::string &id,
const sp<device::V3_2::ICameraDeviceCallback>& callback,
/*out*/
sp<device::V3_2::ICameraDeviceSession> *session) {
@@ -389,21 +529,23 @@
/*minVersion*/ {3,0}, /*maxVersion*/ {4,0});
if (deviceInfo == nullptr) return NAME_NOT_FOUND;
- auto *deviceInfo3 = static_cast<ProviderInfo::DeviceInfo3*>(deviceInfo);
+ auto *hidlDeviceInfo3 = static_cast<HidlProviderInfo::HidlDeviceInfo3*>(deviceInfo);
sp<ProviderInfo> parentProvider = deviceInfo->mParentProvider.promote();
if (parentProvider == nullptr) {
return DEAD_OBJECT;
}
- const sp<provider::V2_4::ICameraProvider> provider = parentProvider->startProviderInterface();
+ const sp<provider::V2_4::ICameraProvider> provider =
+ static_cast<HidlProviderInfo *>(parentProvider.get())->startProviderInterface();
if (provider == nullptr) {
return DEAD_OBJECT;
}
- saveRef(DeviceMode::CAMERA, id, provider);
+ std::shared_ptr<HalCameraProvider> halCameraProvider =
+ std::make_shared<HidlHalCameraProvider>(provider, provider->descriptor);
+ saveRef(DeviceMode::CAMERA, id, halCameraProvider);
Status status;
hardware::Return<void> ret;
- auto interface = deviceInfo3->startDeviceInterface<
- CameraProviderManager::ProviderInfo::DeviceInfo3::InterfaceT>();
+ auto interface = hidlDeviceInfo3->startDeviceInterface();
if (interface == nullptr) {
return DEAD_OBJECT;
}
@@ -421,17 +563,18 @@
__FUNCTION__, id.c_str(), ret.description().c_str());
return DEAD_OBJECT;
}
- return mapToStatusT(status);
+ return HidlProviderInfo::mapToStatusT(status);
}
void CameraProviderManager::saveRef(DeviceMode usageType, const std::string &cameraId,
- sp<provider::V2_4::ICameraProvider> provider) {
+ std::shared_ptr<HalCameraProvider> provider) {
if (!kEnableLazyHal) {
return;
}
- ALOGV("Saving camera provider %s for camera device %s", provider->descriptor, cameraId.c_str());
+ ALOGV("Saving camera provider %s for camera device %s", provider->mDescriptor.c_str(),
+ cameraId.c_str());
std::lock_guard<std::mutex> lock(mProviderInterfaceMapLock);
- std::unordered_map<std::string, sp<provider::V2_4::ICameraProvider>> *primaryMap, *alternateMap;
+ std::unordered_map<std::string, std::shared_ptr<HalCameraProvider>> *primaryMap, *alternateMap;
if (usageType == DeviceMode::TORCH) {
primaryMap = &mTorchProviderByCameraId;
alternateMap = &mCameraProviderByCameraId;
@@ -454,7 +597,7 @@
return;
}
ALOGV("Removing camera device %s", cameraId.c_str());
- std::unordered_map<std::string, sp<provider::V2_4::ICameraProvider>> *providerMap;
+ std::unordered_map<std::string, std::shared_ptr<HalCameraProvider>> *providerMap;
if (usageType == DeviceMode::TORCH) {
providerMap = &mTorchProviderByCameraId;
} else {
@@ -488,7 +631,7 @@
{
std::lock_guard<std::mutex> lock(mInterfaceMutex);
- res = addProviderLocked(name, preexisting);
+ res = addHidlProviderLocked(name, preexisting);
}
sp<StatusListener> listener = getStatusListener();
@@ -1244,10 +1387,10 @@
return falseRet;
}
-status_t CameraProviderManager::tryToInitializeProviderLocked(
+status_t CameraProviderManager::tryToInitializeHidlProviderLocked(
const std::string& providerName, const sp<ProviderInfo>& providerInfo) {
sp<provider::V2_4::ICameraProvider> interface;
- interface = mServiceProxy->tryGetService(providerName);
+ interface = mHidlServiceProxy->tryGetService(providerName);
if (interface == nullptr) {
// The interface may not be started yet. In that case, this is not a
@@ -1257,10 +1400,11 @@
return BAD_VALUE;
}
- return providerInfo->initialize(interface, mDeviceState);
+ HidlProviderInfo *hidlProviderInfo = static_cast<HidlProviderInfo *>(providerInfo.get());
+ return hidlProviderInfo->initializeHidlProvider(interface, mDeviceState);
}
-status_t CameraProviderManager::addProviderLocked(const std::string& newProvider,
+status_t CameraProviderManager::addHidlProviderLocked(const std::string& newProvider,
bool preexisting) {
// Several camera provider instances can be temporarily present.
// Defer initialization of a new instance until the older instance is properly removed.
@@ -1270,9 +1414,10 @@
if (providerInfo->mProviderName == newProvider) {
ALOGW("%s: Camera provider HAL with name '%s' already registered",
__FUNCTION__, newProvider.c_str());
- if (preexisting) {
+ // Do not add new instances for lazy HAL external provider
+ if (preexisting || providerInfo->isExternalLazyHAL()) {
return ALREADY_EXISTS;
- } else{
+ } else {
ALOGW("%s: The new provider instance will get initialized immediately after the"
" currently present instance is removed!", __FUNCTION__);
providerPresent = true;
@@ -1281,9 +1426,9 @@
}
}
- sp<ProviderInfo> providerInfo = new ProviderInfo(newProvider, providerInstance, this);
+ sp<HidlProviderInfo> providerInfo = new HidlProviderInfo(newProvider, providerInstance, this);
if (!providerPresent) {
- status_t res = tryToInitializeProviderLocked(newProvider, providerInfo);
+ status_t res = tryToInitializeHidlProviderLocked(newProvider, providerInfo);
if (res != OK) {
return res;
}
@@ -1321,7 +1466,13 @@
// initialize.
for (const auto& providerInfo : mProviders) {
if (providerInfo->mProviderName == removedProviderName) {
- return tryToInitializeProviderLocked(removedProviderName, providerInfo);
+ IPCTransport providerTransport = providerInfo->getIPCTransport();
+ switch(providerTransport) {
+ case IPCTransport::HIDL:
+ return tryToInitializeHidlProviderLocked(removedProviderName, providerInfo);
+ default:
+ ALOGE("%s Unsupported Transport %d", __FUNCTION__, providerTransport);
+ }
}
}
@@ -1343,7 +1494,6 @@
sp<CameraProviderManager::StatusListener> CameraProviderManager::getStatusListener() const {
return mListener.promote();
}
-
/**** Methods for ProviderInfo ****/
@@ -1359,322 +1509,60 @@
(void) mManager;
}
-status_t CameraProviderManager::ProviderInfo::initialize(
- sp<provider::V2_4::ICameraProvider>& interface,
- hardware::hidl_bitfield<provider::V2_5::DeviceState> currentDeviceState) {
- status_t res = parseProviderName(mProviderName, &mType, &mId);
- if (res != OK) {
- ALOGE("%s: Invalid provider name, ignoring", __FUNCTION__);
- return BAD_VALUE;
- }
- ALOGI("Connecting to new camera provider: %s, isRemote? %d",
- mProviderName.c_str(), interface->isRemote());
-
- // Determine minor version
- mMinorVersion = 4;
- auto cast2_6 = provider::V2_6::ICameraProvider::castFrom(interface);
- sp<provider::V2_6::ICameraProvider> interface2_6 = nullptr;
- if (cast2_6.isOk()) {
- interface2_6 = cast2_6;
- if (interface2_6 != nullptr) {
- mMinorVersion = 6;
- }
- }
- // We need to check again since cast2_6.isOk() succeeds even if the provider
- // version isn't actually 2.6.
- if (interface2_6 == nullptr){
- auto cast2_5 =
- provider::V2_5::ICameraProvider::castFrom(interface);
- sp<provider::V2_5::ICameraProvider> interface2_5 = nullptr;
- if (cast2_5.isOk()) {
- interface2_5 = cast2_5;
- if (interface != nullptr) {
- 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)
- // before setCallback returns
- hardware::Return<Status> status = interface->setCallback(this);
- if (!status.isOk()) {
- ALOGE("%s: Transaction error setting up callbacks with camera provider '%s': %s",
- __FUNCTION__, mProviderName.c_str(), status.description().c_str());
- return DEAD_OBJECT;
- }
- if (status != Status::OK) {
- ALOGE("%s: Unable to register callbacks with camera provider '%s'",
- __FUNCTION__, mProviderName.c_str());
- return mapToStatusT(status);
- }
-
- hardware::Return<bool> linked = interface->linkToDeath(this, /*cookie*/ mId);
- if (!linked.isOk()) {
- ALOGE("%s: Transaction error in linking to camera provider '%s' death: %s",
- __FUNCTION__, mProviderName.c_str(), linked.description().c_str());
- return DEAD_OBJECT;
- } else if (!linked) {
- ALOGW("%s: Unable to link to provider '%s' death notifications",
- __FUNCTION__, mProviderName.c_str());
- }
-
- if (!kEnableLazyHal) {
- // Save HAL reference indefinitely
- mSavedInterface = interface;
- } else {
- mActiveInterface = interface;
- }
-
- ALOGV("%s: Setting device state for %s: 0x%" PRIx64,
- __FUNCTION__, mProviderName.c_str(), mDeviceState);
- notifyDeviceStateChange(currentDeviceState);
-
- res = setUpVendorTags();
- if (res != OK) {
- ALOGE("%s: Unable to set up vendor tags from provider '%s'",
- __FUNCTION__, mProviderName.c_str());
- return res;
- }
-
- // Get initial list of camera devices, if any
- std::vector<std::string> devices;
- hardware::Return<void> ret = interface->getCameraIdList([&status, this, &devices](
- Status idStatus,
- const hardware::hidl_vec<hardware::hidl_string>& cameraDeviceNames) {
- status = idStatus;
- if (status == Status::OK) {
- for (auto& name : cameraDeviceNames) {
- uint16_t major, minor;
- std::string type, id;
- status_t res = parseDeviceName(name, &major, &minor, &type, &id);
- if (res != OK) {
- ALOGE("%s: Error parsing deviceName: %s: %d", __FUNCTION__, name.c_str(), res);
- status = Status::INTERNAL_ERROR;
- } else {
- devices.push_back(name);
- mProviderPublicCameraIds.push_back(id);
- }
- }
- } });
- if (!ret.isOk()) {
- ALOGE("%s: Transaction error in getting camera ID list from provider '%s': %s",
- __FUNCTION__, mProviderName.c_str(), linked.description().c_str());
- return DEAD_OBJECT;
- }
- if (status != Status::OK) {
- ALOGE("%s: Unable to query for camera devices from provider '%s'",
- __FUNCTION__, mProviderName.c_str());
- return mapToStatusT(status);
- }
-
- // Get list of concurrent streaming camera device combinations
- if (mMinorVersion >= 6) {
- res = getConcurrentCameraIdsInternalLocked(interface2_6);
- if (res != OK) {
- return res;
- }
- }
-
- ret = interface->isSetTorchModeSupported(
- [this](auto status, bool supported) {
- if (status == Status::OK) {
- mSetTorchModeSupported = supported;
- }
- });
- if (!ret.isOk()) {
- ALOGE("%s: Transaction error checking torch mode support '%s': %s",
- __FUNCTION__, mProviderName.c_str(), ret.description().c_str());
- return DEAD_OBJECT;
- }
-
- mIsRemote = interface->isRemote();
-
- sp<StatusListener> listener = mManager->getStatusListener();
- for (auto& device : devices) {
- std::string id;
- status_t res = addDevice(device, common::V1_0::CameraDeviceStatus::PRESENT, &id);
- if (res != OK) {
- ALOGE("%s: Unable to enumerate camera device '%s': %s (%d)",
- __FUNCTION__, device.c_str(), strerror(-res), res);
- continue;
- }
- }
-
- ALOGI("Camera provider %s ready with %zu camera devices",
- mProviderName.c_str(), mDevices.size());
-
- // Process cached status callbacks
- std::unique_ptr<std::vector<CameraStatusInfoT>> cachedStatus =
- std::make_unique<std::vector<CameraStatusInfoT>>();
- {
- std::lock_guard<std::mutex> lock(mInitLock);
-
- for (auto& statusInfo : mCachedStatus) {
- std::string id, physicalId;
- status_t res = OK;
- if (statusInfo.isPhysicalCameraStatus) {
- res = physicalCameraDeviceStatusChangeLocked(&id, &physicalId,
- statusInfo.cameraId, statusInfo.physicalCameraId, statusInfo.status);
- } else {
- res = cameraDeviceStatusChangeLocked(&id, statusInfo.cameraId, statusInfo.status);
- }
- if (res == OK) {
- cachedStatus->emplace_back(statusInfo.isPhysicalCameraStatus,
- id.c_str(), physicalId.c_str(), statusInfo.status);
- }
- }
- mCachedStatus.clear();
-
- mInitialized = true;
- }
-
- // The cached status change callbacks cannot be fired directly from this
- // function, due to same-thread deadlock trying to acquire mInterfaceMutex
- // twice.
- if (listener != nullptr) {
- mInitialStatusCallbackFuture = std::async(std::launch::async,
- &CameraProviderManager::ProviderInfo::notifyInitialStatusChange, this,
- listener, std::move(cachedStatus));
- }
-
- return OK;
-}
-
-const sp<provider::V2_4::ICameraProvider>
-CameraProviderManager::ProviderInfo::startProviderInterface() {
- ATRACE_CALL();
- ALOGV("Request to start camera provider: %s", mProviderName.c_str());
- if (mSavedInterface != nullptr) {
- return mSavedInterface;
- }
- if (!kEnableLazyHal) {
- ALOGE("Bad provider state! Should not be here on a non-lazy HAL!");
- return nullptr;
- }
-
- auto interface = mActiveInterface.promote();
- if (interface == nullptr) {
- ALOGI("Camera HAL provider needs restart, calling getService(%s)", mProviderName.c_str());
- interface = mManager->mServiceProxy->getService(mProviderName);
- interface->setCallback(this);
- hardware::Return<bool> linked = interface->linkToDeath(this, /*cookie*/ mId);
- if (!linked.isOk()) {
- ALOGE("%s: Transaction error in linking to camera provider '%s' death: %s",
- __FUNCTION__, mProviderName.c_str(), linked.description().c_str());
- mManager->removeProvider(mProviderName);
- return nullptr;
- } else if (!linked) {
- ALOGW("%s: Unable to link to provider '%s' death notifications",
- __FUNCTION__, mProviderName.c_str());
- }
- // Send current device state
- if (mMinorVersion >= 5) {
- auto castResult = provider::V2_5::ICameraProvider::castFrom(interface);
- if (castResult.isOk()) {
- sp<provider::V2_5::ICameraProvider> interface_2_5 = castResult;
- if (interface_2_5 != nullptr) {
- ALOGV("%s: Initial device state for %s: 0x %" PRIx64,
- __FUNCTION__, mProviderName.c_str(), mDeviceState);
- interface_2_5->notifyDeviceStateChange(mDeviceState);
- }
- }
- }
-
- mActiveInterface = interface;
- } else {
- ALOGV("Camera provider (%s) already in use. Re-using instance.", mProviderName.c_str());
- }
- return interface;
-}
-
const std::string& CameraProviderManager::ProviderInfo::getType() const {
return mType;
}
-status_t CameraProviderManager::ProviderInfo::addDevice(const std::string& name,
- CameraDeviceStatus initialStatus, /*out*/ std::string* parsedId) {
-
- ALOGI("Enumerating new camera device: %s", name.c_str());
-
- uint16_t major, minor;
- std::string type, id;
-
- status_t res = parseDeviceName(name, &major, &minor, &type, &id);
- if (res != OK) {
- return res;
- }
- if (type != mType) {
- ALOGE("%s: Device type %s does not match provider type %s", __FUNCTION__,
- type.c_str(), mType.c_str());
- return BAD_VALUE;
- }
- if (mManager->isValidDeviceLocked(id, major)) {
- ALOGE("%s: Device %s: ID %s is already in use for device major version %d", __FUNCTION__,
- name.c_str(), id.c_str(), major);
- return BAD_VALUE;
- }
-
- std::unique_ptr<DeviceInfo> deviceInfo;
- switch (major) {
- case 1:
- ALOGE("%s: Device %s: Unsupported HIDL device HAL major version %d:", __FUNCTION__,
- name.c_str(), major);
- return BAD_VALUE;
- case 3:
- deviceInfo = initializeDeviceInfo<DeviceInfo3>(name, mProviderTagid,
- id, minor);
- break;
- default:
- ALOGE("%s: Device %s: Unknown HIDL device HAL major version %d:", __FUNCTION__,
- name.c_str(), major);
- return BAD_VALUE;
- }
- if (deviceInfo == nullptr) return BAD_VALUE;
- deviceInfo->notifyDeviceStateChange(mDeviceState);
- deviceInfo->mStatus = initialStatus;
- bool isAPI1Compatible = deviceInfo->isAPI1Compatible();
-
- mDevices.push_back(std::move(deviceInfo));
-
- mUniqueCameraIds.insert(id);
- if (isAPI1Compatible) {
- // addDevice can be called more than once for the same camera id if HAL
- // supports openLegacy.
- if (std::find(mUniqueAPI1CompatibleCameraIds.begin(), mUniqueAPI1CompatibleCameraIds.end(),
- id) == mUniqueAPI1CompatibleCameraIds.end()) {
- mUniqueAPI1CompatibleCameraIds.push_back(id);
- }
- }
-
- if (parsedId != nullptr) {
- *parsedId = id;
- }
- return OK;
-}
-
void CameraProviderManager::ProviderInfo::removeDevice(std::string id) {
for (auto it = mDevices.begin(); it != mDevices.end(); it++) {
if ((*it)->mId == id) {
mUniqueCameraIds.erase(id);
if ((*it)->isAPI1Compatible()) {
mUniqueAPI1CompatibleCameraIds.erase(std::remove(
- mUniqueAPI1CompatibleCameraIds.begin(),
- mUniqueAPI1CompatibleCameraIds.end(), id));
+ mUniqueAPI1CompatibleCameraIds.begin(),
+ mUniqueAPI1CompatibleCameraIds.end(), id));
}
+
+ // Remove reference to camera provider to avoid pointer leak when
+ // unplugging external camera while in use with lazy HALs
+ mManager->removeRef(DeviceMode::CAMERA, id);
+ mManager->removeRef(DeviceMode::TORCH, id);
+
mDevices.erase(it);
break;
}
}
}
+void CameraProviderManager::ProviderInfo::removeAllDevices() {
+ std::lock_guard<std::mutex> lock(mLock);
+
+ auto itDevices = mDevices.begin();
+ while (itDevices != mDevices.end()) {
+ std::string id = (*itDevices)->mId;
+ std::string deviceName = (*itDevices)->mName;
+ removeDevice(id);
+ // device was removed, reset iterator
+ itDevices = mDevices.begin();
+
+ //notify CameraService of status change
+ sp<StatusListener> listener = mManager->getStatusListener();
+ if (listener != nullptr) {
+ mLock.unlock();
+ ALOGV("%s: notify device not_present: %s",
+ __FUNCTION__,
+ deviceName.c_str());
+ listener->onDeviceStatusChanged(String8(id.c_str()),
+ CameraDeviceStatus::NOT_PRESENT);
+ mLock.lock();
+ }
+ }
+}
+
+bool CameraProviderManager::ProviderInfo::isExternalLazyHAL() const {
+ return kEnableLazyHal && (mProviderName == kExternalProviderName);
+}
+
status_t CameraProviderManager::ProviderInfo::dump(int fd, const Vector<String16>&) const {
dprintf(fd, "== Camera Provider HAL %s (v2.%d, %s) static info: %zu devices: ==\n",
mProviderInstance.c_str(),
@@ -1749,416 +1637,20 @@
return OK;
}
-status_t CameraProviderManager::ProviderInfo::getConcurrentCameraIdsInternalLocked(
- sp<provider::V2_6::ICameraProvider> &interface2_6) {
- if (interface2_6 == nullptr) {
- ALOGE("%s: null interface provided", __FUNCTION__);
- return BAD_VALUE;
- }
- Status status = Status::OK;
- hardware::Return<void> ret =
- interface2_6->getConcurrentStreamingCameraIds([&status, this](
- Status concurrentIdStatus, // TODO: Move all instances of hidl_string to 'using'
- const hardware::hidl_vec<hardware::hidl_vec<hardware::hidl_string>>&
- cameraDeviceIdCombinations) {
- status = concurrentIdStatus;
- if (status == Status::OK) {
- mConcurrentCameraIdCombinations.clear();
- for (auto& combination : cameraDeviceIdCombinations) {
- std::unordered_set<std::string> deviceIds;
- for (auto &cameraDeviceId : combination) {
- deviceIds.insert(cameraDeviceId.c_str());
- }
- mConcurrentCameraIdCombinations.push_back(std::move(deviceIds));
- }
- } });
- if (!ret.isOk()) {
- ALOGE("%s: Transaction error in getting concurrent camera ID list from provider '%s'",
- __FUNCTION__, mProviderName.c_str());
- return DEAD_OBJECT;
- }
- if (status != Status::OK) {
- ALOGE("%s: Unable to query for camera devices from provider '%s'",
- __FUNCTION__, mProviderName.c_str());
- return mapToStatusT(status);
- }
- return OK;
-}
-
-status_t CameraProviderManager::ProviderInfo::reCacheConcurrentStreamingCameraIdsLocked() {
- if (mMinorVersion < 6) {
- // Unsupported operation, nothing to do here
- return OK;
- }
- // Check if the provider is currently active - not going to start it up for this notification
- auto interface = mSavedInterface != nullptr ? mSavedInterface : mActiveInterface.promote();
- if (interface == nullptr) {
- ALOGE("%s: camera provider interface for %s is not valid", __FUNCTION__,
- mProviderName.c_str());
- return INVALID_OPERATION;
- }
- auto castResult = provider::V2_6::ICameraProvider::castFrom(interface);
-
- if (castResult.isOk()) {
- sp<provider::V2_6::ICameraProvider> interface2_6 = castResult;
- if (interface2_6 != nullptr) {
- return getConcurrentCameraIdsInternalLocked(interface2_6);
- } else {
- // This should not happen since mMinorVersion >= 6
- ALOGE("%s: mMinorVersion was >= 6, but interface2_6 was nullptr", __FUNCTION__);
- return UNKNOWN_ERROR;
- }
- }
- return OK;
-}
-
std::vector<std::unordered_set<std::string>>
CameraProviderManager::ProviderInfo::getConcurrentCameraIdCombinations() {
std::lock_guard<std::mutex> lock(mLock);
return mConcurrentCameraIdCombinations;
}
-hardware::Return<void> CameraProviderManager::ProviderInfo::cameraDeviceStatusChange(
- const hardware::hidl_string& cameraDeviceName,
- CameraDeviceStatus newStatus) {
- sp<StatusListener> listener;
- std::string id;
- std::lock_guard<std::mutex> lock(mInitLock);
-
- if (!mInitialized) {
- mCachedStatus.emplace_back(false /*isPhysicalCameraStatus*/,
- cameraDeviceName.c_str(), std::string().c_str(), newStatus);
- return hardware::Void();
- }
-
- {
- std::lock_guard<std::mutex> lock(mLock);
- if (OK != cameraDeviceStatusChangeLocked(&id, cameraDeviceName, newStatus)) {
- return hardware::Void();
- }
- listener = mManager->getStatusListener();
- }
-
- // Call without lock held to allow reentrancy into provider manager
- if (listener != nullptr) {
- listener->onDeviceStatusChanged(String8(id.c_str()), newStatus);
- }
-
- return hardware::Void();
-}
-
-status_t CameraProviderManager::ProviderInfo::cameraDeviceStatusChangeLocked(
- std::string* id, const hardware::hidl_string& cameraDeviceName,
- CameraDeviceStatus newStatus) {
- bool known = false;
- std::string cameraId;
- for (auto& deviceInfo : mDevices) {
- if (deviceInfo->mName == cameraDeviceName) {
- ALOGI("Camera device %s status is now %s, was %s", cameraDeviceName.c_str(),
- deviceStatusToString(newStatus), deviceStatusToString(deviceInfo->mStatus));
- deviceInfo->mStatus = newStatus;
- // TODO: Handle device removal (NOT_PRESENT)
- cameraId = deviceInfo->mId;
- known = true;
- break;
- }
- }
- // Previously unseen device; status must not be NOT_PRESENT
- if (!known) {
- if (newStatus == CameraDeviceStatus::NOT_PRESENT) {
- ALOGW("Camera provider %s says an unknown camera device %s is not present. Curious.",
- mProviderName.c_str(), cameraDeviceName.c_str());
- return BAD_VALUE;
- }
- addDevice(cameraDeviceName, newStatus, &cameraId);
- } else if (newStatus == CameraDeviceStatus::NOT_PRESENT) {
- removeDevice(cameraId);
- }
- if (reCacheConcurrentStreamingCameraIdsLocked() != OK) {
- ALOGE("%s: CameraProvider %s could not re-cache concurrent streaming camera id list ",
- __FUNCTION__, mProviderName.c_str());
- }
- *id = cameraId;
- return OK;
-}
-
-hardware::Return<void> CameraProviderManager::ProviderInfo::physicalCameraDeviceStatusChange(
- const hardware::hidl_string& cameraDeviceName,
- const hardware::hidl_string& physicalCameraDeviceName,
- CameraDeviceStatus newStatus) {
- sp<StatusListener> listener;
- std::string id;
- std::string physicalId;
- std::lock_guard<std::mutex> lock(mInitLock);
-
- if (!mInitialized) {
- mCachedStatus.emplace_back(true /*isPhysicalCameraStatus*/, cameraDeviceName,
- physicalCameraDeviceName, newStatus);
- return hardware::Void();
- }
-
- {
- std::lock_guard<std::mutex> lock(mLock);
-
- if (OK != physicalCameraDeviceStatusChangeLocked(&id, &physicalId, cameraDeviceName,
- physicalCameraDeviceName, newStatus)) {
- return hardware::Void();
- }
-
- listener = mManager->getStatusListener();
- }
- // Call without lock held to allow reentrancy into provider manager
- if (listener != nullptr) {
- listener->onDeviceStatusChanged(String8(id.c_str()),
- String8(physicalId.c_str()), newStatus);
- }
- return hardware::Void();
-}
-
-status_t CameraProviderManager::ProviderInfo::physicalCameraDeviceStatusChangeLocked(
- std::string* id, std::string* physicalId,
- const hardware::hidl_string& cameraDeviceName,
- const hardware::hidl_string& physicalCameraDeviceName,
- CameraDeviceStatus newStatus) {
- bool known = false;
- std::string cameraId;
- for (auto& deviceInfo : mDevices) {
- if (deviceInfo->mName == cameraDeviceName) {
- cameraId = deviceInfo->mId;
- if (!deviceInfo->mIsLogicalCamera) {
- ALOGE("%s: Invalid combination of camera id %s, physical id %s",
- __FUNCTION__, cameraId.c_str(), physicalCameraDeviceName.c_str());
- return BAD_VALUE;
- }
- if (std::find(deviceInfo->mPhysicalIds.begin(), deviceInfo->mPhysicalIds.end(),
- physicalCameraDeviceName) == deviceInfo->mPhysicalIds.end()) {
- ALOGE("%s: Invalid combination of camera id %s, physical id %s",
- __FUNCTION__, cameraId.c_str(), physicalCameraDeviceName.c_str());
- return BAD_VALUE;
- }
- ALOGI("Camera device %s physical device %s status is now %s",
- cameraDeviceName.c_str(), physicalCameraDeviceName.c_str(),
- deviceStatusToString(newStatus));
- known = true;
- break;
- }
- }
- // Previously unseen device; status must not be NOT_PRESENT
- if (!known) {
- ALOGW("Camera provider %s says an unknown camera device %s-%s is not present. Curious.",
- mProviderName.c_str(), cameraDeviceName.c_str(),
- physicalCameraDeviceName.c_str());
- return BAD_VALUE;
- }
-
- *id = cameraId;
- *physicalId = physicalCameraDeviceName.c_str();
- return OK;
-}
-
-hardware::Return<void> CameraProviderManager::ProviderInfo::torchModeStatusChange(
- const hardware::hidl_string& cameraDeviceName,
- TorchModeStatus newStatus) {
- sp<StatusListener> listener;
- SystemCameraKind systemCameraKind = SystemCameraKind::PUBLIC;
- std::string id;
- bool known = false;
- {
- // Hold mLock for accessing mDevices
- std::lock_guard<std::mutex> lock(mLock);
- for (auto& deviceInfo : mDevices) {
- if (deviceInfo->mName == cameraDeviceName) {
- ALOGI("Camera device %s torch status is now %s", cameraDeviceName.c_str(),
- torchStatusToString(newStatus));
- id = deviceInfo->mId;
- known = true;
- systemCameraKind = deviceInfo->mSystemCameraKind;
- if (TorchModeStatus::AVAILABLE_ON != newStatus) {
- mManager->removeRef(DeviceMode::TORCH, id);
- }
- break;
- }
- }
- if (!known) {
- ALOGW("Camera provider %s says an unknown camera %s now has torch status %d. Curious.",
- mProviderName.c_str(), cameraDeviceName.c_str(), newStatus);
- return hardware::Void();
- }
- // no lock needed since listener is set up only once during
- // CameraProviderManager initialization and then never changed till it is
- // destructed.
- listener = mManager->getStatusListener();
- }
- // Call without lock held to allow reentrancy into provider manager
- // The problem with holding mLock here is that we
- // might be limiting re-entrancy : CameraService::onTorchStatusChanged calls
- // back into CameraProviderManager which might try to hold mLock again (eg:
- // findDeviceInfo, which should be holding mLock while iterating through
- // each provider's devices).
- if (listener != nullptr) {
- listener->onTorchStatusChanged(String8(id.c_str()), newStatus, systemCameraKind);
- }
- return hardware::Void();
-}
-
-void CameraProviderManager::ProviderInfo::serviceDied(uint64_t cookie,
- const wp<hidl::base::V1_0::IBase>& who) {
- (void) who;
- ALOGI("Camera provider '%s' has died; removing it", mProviderInstance.c_str());
- if (cookie != mId) {
- ALOGW("%s: Unexpected serviceDied cookie %" PRIu64 ", expected %" PRIu32,
- __FUNCTION__, cookie, mId);
- }
- mManager->removeProvider(mProviderInstance);
-}
-
-status_t CameraProviderManager::ProviderInfo::setUpVendorTags() {
- if (mVendorTagDescriptor != nullptr)
- return OK;
-
- hardware::hidl_vec<VendorTagSection> vts;
- Status status;
- hardware::Return<void> ret;
- const sp<provider::V2_4::ICameraProvider> interface = startProviderInterface();
- if (interface == nullptr) {
- return DEAD_OBJECT;
- }
- ret = interface->getVendorTags(
- [&](auto s, const auto& vendorTagSecs) {
- status = s;
- if (s == Status::OK) {
- vts = vendorTagSecs;
- }
- });
- if (!ret.isOk()) {
- ALOGE("%s: Transaction error getting vendor tags from provider '%s': %s",
- __FUNCTION__, mProviderName.c_str(), ret.description().c_str());
- return DEAD_OBJECT;
- }
- if (status != Status::OK) {
- return mapToStatusT(status);
- }
-
- // Read all vendor tag definitions into a descriptor
- status_t res;
- if ((res = HidlVendorTagDescriptor::createDescriptorFromHidl(vts, /*out*/mVendorTagDescriptor))
- != OK) {
- ALOGE("%s: Could not generate descriptor from vendor tag operations,"
- "received error %s (%d). Camera clients will not be able to use"
- "vendor tags", __FUNCTION__, strerror(res), res);
- return res;
- }
-
- return OK;
-}
-
void CameraProviderManager::ProviderInfo::notifyDeviceInfoStateChangeLocked(
- hardware::hidl_bitfield<provider::V2_5::DeviceState> newDeviceState) {
+ int64_t newDeviceState) {
std::lock_guard<std::mutex> lock(mLock);
for (auto it = mDevices.begin(); it != mDevices.end(); it++) {
(*it)->notifyDeviceStateChange(newDeviceState);
}
}
-status_t CameraProviderManager::ProviderInfo::notifyDeviceStateChange(
- hardware::hidl_bitfield<provider::V2_5::DeviceState> newDeviceState) {
- mDeviceState = newDeviceState;
- if (mMinorVersion >= 5) {
- // Check if the provider is currently active - not going to start it up for this notification
- auto interface = mSavedInterface != nullptr ? mSavedInterface : mActiveInterface.promote();
- if (interface != nullptr) {
- // Send current device state
- auto castResult = provider::V2_5::ICameraProvider::castFrom(interface);
- if (castResult.isOk()) {
- sp<provider::V2_5::ICameraProvider> interface_2_5 = castResult;
- if (interface_2_5 != nullptr) {
- interface_2_5->notifyDeviceStateChange(mDeviceState);
- }
- }
- }
- }
- return OK;
-}
-
-status_t CameraProviderManager::ProviderInfo::isConcurrentSessionConfigurationSupported(
- const hardware::hidl_vec<CameraIdAndStreamCombination> &halCameraIdsAndStreamCombinations,
- bool *isSupported) {
- status_t res = OK;
- if (mMinorVersion >= 6) {
- // Check if the provider is currently active - not going to start it up for this notification
- auto interface = mSavedInterface != nullptr ? mSavedInterface : mActiveInterface.promote();
- if (interface == nullptr) {
- // TODO: This might be some other problem
- return INVALID_OPERATION;
- }
- 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; };
-
- ::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++) {
- using namespace camera3;
- 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
- return INVALID_OPERATION;
-}
-
void CameraProviderManager::ProviderInfo::notifyInitialStatusChange(
sp<StatusListener> listener,
std::unique_ptr<std::vector<CameraStatusInfoT>> cachedStatus) {
@@ -2173,290 +1665,16 @@
}
}
-template<class DeviceInfoT>
-std::unique_ptr<CameraProviderManager::ProviderInfo::DeviceInfo>
- CameraProviderManager::ProviderInfo::initializeDeviceInfo(
- const std::string &name, const metadata_vendor_id_t tagId,
- const std::string &id, uint16_t minorVersion) {
- Status status;
-
- auto cameraInterface =
- startDeviceInterface<typename DeviceInfoT::InterfaceT>(name);
- if (cameraInterface == nullptr) return nullptr;
-
- CameraResourceCost resourceCost;
- cameraInterface->getResourceCost([&status, &resourceCost](
- Status s, CameraResourceCost cost) {
- status = s;
- resourceCost = cost;
- });
- if (status != Status::OK) {
- ALOGE("%s: Unable to obtain resource costs for camera device %s: %s", __FUNCTION__,
- name.c_str(), statusToString(status));
- return nullptr;
- }
-
- for (auto& conflictName : resourceCost.conflictingDevices) {
- uint16_t major, minor;
- std::string type, id;
- status_t res = parseDeviceName(conflictName, &major, &minor, &type, &id);
- if (res != OK) {
- ALOGE("%s: Failed to parse conflicting device %s", __FUNCTION__, conflictName.c_str());
- return nullptr;
- }
- conflictName = id;
- }
-
- return std::unique_ptr<DeviceInfo>(
- new DeviceInfoT(name, tagId, id, minorVersion, resourceCost, this,
- mProviderPublicCameraIds, cameraInterface));
-}
-
-template<class InterfaceT>
-sp<InterfaceT>
-CameraProviderManager::ProviderInfo::startDeviceInterface(const std::string &name) {
- ALOGE("%s: Device %s: Unknown HIDL device HAL major version %d:", __FUNCTION__,
- name.c_str(), InterfaceT::version.get_major());
- return nullptr;
-}
-
-template<>
-sp<device::V3_2::ICameraDevice>
-CameraProviderManager::ProviderInfo::startDeviceInterface
- <device::V3_2::ICameraDevice>(const std::string &name) {
- Status status;
- sp<device::V3_2::ICameraDevice> cameraInterface;
- hardware::Return<void> ret;
- const sp<provider::V2_4::ICameraProvider> interface = startProviderInterface();
- if (interface == nullptr) {
- return nullptr;
- }
- ret = interface->getCameraDeviceInterface_V3_x(name, [&status, &cameraInterface](
- Status s, sp<device::V3_2::ICameraDevice> interface) {
- status = s;
- cameraInterface = interface;
- });
- if (!ret.isOk()) {
- ALOGE("%s: Transaction error trying to obtain interface for camera device %s: %s",
- __FUNCTION__, name.c_str(), ret.description().c_str());
- return nullptr;
- }
- if (status != Status::OK) {
- ALOGE("%s: Unable to obtain interface for camera device %s: %s", __FUNCTION__,
- name.c_str(), statusToString(status));
- return nullptr;
- }
- return cameraInterface;
-}
-
-CameraProviderManager::ProviderInfo::DeviceInfo::~DeviceInfo() {}
-
-template<class InterfaceT>
-sp<InterfaceT> CameraProviderManager::ProviderInfo::DeviceInfo::startDeviceInterface() {
- sp<InterfaceT> device;
- ATRACE_CALL();
- if (mSavedInterface == nullptr) {
- sp<ProviderInfo> parentProvider = mParentProvider.promote();
- if (parentProvider != nullptr) {
- device = parentProvider->startDeviceInterface<InterfaceT>(mName);
- }
- } else {
- device = (InterfaceT *) mSavedInterface.get();
- }
- return device;
-}
-
-template<class InterfaceT>
-status_t CameraProviderManager::ProviderInfo::DeviceInfo::setTorchMode(InterfaceT& interface,
- bool enabled) {
- Status s = interface->setTorchMode(enabled ? TorchMode::ON : TorchMode::OFF);
- return mapToStatusT(s);
-}
-
CameraProviderManager::ProviderInfo::DeviceInfo3::DeviceInfo3(const std::string& name,
const metadata_vendor_id_t tagId, const std::string &id,
uint16_t minorVersion,
const CameraResourceCost& resourceCost,
sp<ProviderInfo> parentProvider,
- const std::vector<std::string>& publicCameraIds,
- sp<InterfaceT> interface) :
+ const std::vector<std::string>& publicCameraIds) :
DeviceInfo(name, tagId, id, hardware::hidl_version{3, minorVersion},
- publicCameraIds, resourceCost, parentProvider) {
- // Get camera characteristics and initialize flash unit availability
- Status status;
- hardware::Return<void> ret;
- ret = interface->getCameraCharacteristics([&status, this](Status s,
- device::V3_2::CameraMetadata metadata) {
- status = s;
- if (s == Status::OK) {
- camera_metadata_t *buffer =
- reinterpret_cast<camera_metadata_t*>(metadata.data());
- size_t expectedSize = metadata.size();
- int res = validate_camera_metadata_structure(buffer, &expectedSize);
- if (res == OK || res == CAMERA_METADATA_VALIDATION_SHIFTED) {
- set_camera_metadata_vendor_id(buffer, mProviderTagid);
- mCameraCharacteristics = buffer;
- } else {
- ALOGE("%s: Malformed camera metadata received from HAL", __FUNCTION__);
- status = Status::INTERNAL_ERROR;
- }
- }
- });
- if (!ret.isOk()) {
- ALOGE("%s: Transaction error getting camera characteristics for device %s"
- " to check for a flash unit: %s", __FUNCTION__, id.c_str(),
- ret.description().c_str());
- return;
- }
- if (status != Status::OK) {
- ALOGE("%s: Unable to get camera characteristics for device %s: %s (%d)",
- __FUNCTION__, id.c_str(), CameraProviderManager::statusToString(status), status);
- return;
- }
+ publicCameraIds, resourceCost, parentProvider) { }
- if (mCameraCharacteristics.exists(ANDROID_INFO_DEVICE_STATE_ORIENTATIONS)) {
- const auto &stateMap = mCameraCharacteristics.find(ANDROID_INFO_DEVICE_STATE_ORIENTATIONS);
- if ((stateMap.count > 0) && ((stateMap.count % 2) == 0)) {
- for (size_t i = 0; i < stateMap.count; i += 2) {
- mDeviceStateOrientationMap.emplace(stateMap.data.i64[i], stateMap.data.i64[i+1]);
- }
- } else {
- ALOGW("%s: Invalid ANDROID_INFO_DEVICE_STATE_ORIENTATIONS map size: %zu", __FUNCTION__,
- stateMap.count);
- }
- }
-
- mSystemCameraKind = getSystemCameraKind();
-
- status_t res = fixupMonochromeTags();
- if (OK != res) {
- ALOGE("%s: Unable to fix up monochrome tags based for older HAL version: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- return;
- }
- auto stat = addDynamicDepthTags();
- if (OK != stat) {
- ALOGE("%s: Failed appending dynamic depth tags: %s (%d)", __FUNCTION__, strerror(-stat),
- stat);
- }
- res = deriveHeicTags();
- if (OK != res) {
- ALOGE("%s: Unable to derive HEIC tags based on camera and media capabilities: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- }
-
- if (SessionConfigurationUtils::isUltraHighResolutionSensor(mCameraCharacteristics)) {
- status_t status = addDynamicDepthTags(/*maxResolution*/true);
- if (OK != status) {
- ALOGE("%s: Failed appending dynamic depth tags for maximum resolution mode: %s (%d)",
- __FUNCTION__, strerror(-status), status);
- }
-
- status = deriveHeicTags(/*maxResolution*/true);
- if (OK != status) {
- ALOGE("%s: Unable to derive HEIC tags based on camera and media capabilities for"
- "maximum resolution mode: %s (%d)", __FUNCTION__, strerror(-status), status);
- }
- }
-
- res = addRotateCropTags();
- if (OK != res) {
- ALOGE("%s: Unable to add default SCALER_ROTATE_AND_CROP tags: %s (%d)", __FUNCTION__,
- strerror(-res), res);
- }
- res = addPreCorrectionActiveArraySize();
- if (OK != res) {
- ALOGE("%s: Unable to add PRE_CORRECTION_ACTIVE_ARRAY_SIZE: %s (%d)", __FUNCTION__,
- strerror(-res), res);
- }
- res = camera3::ZoomRatioMapper::overrideZoomRatioTags(
- &mCameraCharacteristics, &mSupportNativeZoomRatio);
- if (OK != res) {
- ALOGE("%s: Unable to override zoomRatio related tags: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- }
-
- camera_metadata_entry flashAvailable =
- mCameraCharacteristics.find(ANDROID_FLASH_INFO_AVAILABLE);
- if (flashAvailable.count == 1 &&
- flashAvailable.data.u8[0] == ANDROID_FLASH_INFO_AVAILABLE_TRUE) {
- mHasFlashUnit = true;
- } else {
- mHasFlashUnit = false;
- }
-
- queryPhysicalCameraIds();
-
- // Get physical camera characteristics if applicable
- auto castResult = device::V3_5::ICameraDevice::castFrom(interface);
- if (!castResult.isOk()) {
- ALOGV("%s: Unable to convert ICameraDevice instance to version 3.5", __FUNCTION__);
- return;
- }
- sp<device::V3_5::ICameraDevice> interface_3_5 = castResult;
- if (interface_3_5 == nullptr) {
- ALOGE("%s: Converted ICameraDevice instance to nullptr", __FUNCTION__);
- return;
- }
-
- if (mIsLogicalCamera) {
- for (auto& id : mPhysicalIds) {
- if (std::find(mPublicCameraIds.begin(), mPublicCameraIds.end(), id) !=
- mPublicCameraIds.end()) {
- continue;
- }
-
- hardware::hidl_string hidlId(id);
- ret = interface_3_5->getPhysicalCameraCharacteristics(hidlId,
- [&status, &id, this](Status s, device::V3_2::CameraMetadata metadata) {
- status = s;
- if (s == Status::OK) {
- camera_metadata_t *buffer =
- reinterpret_cast<camera_metadata_t*>(metadata.data());
- size_t expectedSize = metadata.size();
- int res = validate_camera_metadata_structure(buffer, &expectedSize);
- if (res == OK || res == CAMERA_METADATA_VALIDATION_SHIFTED) {
- set_camera_metadata_vendor_id(buffer, mProviderTagid);
- mPhysicalCameraCharacteristics[id] = buffer;
- } else {
- ALOGE("%s: Malformed camera metadata received from HAL", __FUNCTION__);
- status = Status::INTERNAL_ERROR;
- }
- }
- });
-
- if (!ret.isOk()) {
- ALOGE("%s: Transaction error getting physical camera %s characteristics for %s: %s",
- __FUNCTION__, id.c_str(), id.c_str(), ret.description().c_str());
- return;
- }
- if (status != Status::OK) {
- ALOGE("%s: Unable to get physical camera %s characteristics for device %s: %s (%d)",
- __FUNCTION__, id.c_str(), mId.c_str(),
- CameraProviderManager::statusToString(status), status);
- return;
- }
-
- res = camera3::ZoomRatioMapper::overrideZoomRatioTags(
- &mPhysicalCameraCharacteristics[id], &mSupportNativeZoomRatio);
- if (OK != res) {
- ALOGE("%s: Unable to override zoomRatio related tags: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- }
- }
- }
-
- if (!kEnableLazyHal) {
- // Save HAL reference indefinitely
- mSavedInterface = interface;
- }
-}
-
-CameraProviderManager::ProviderInfo::DeviceInfo3::~DeviceInfo3() {}
-
-void CameraProviderManager::ProviderInfo::DeviceInfo3::notifyDeviceStateChange(
- hardware::hidl_bitfield<hardware::camera::provider::V2_5::DeviceState> newState) {
-
+void CameraProviderManager::ProviderInfo::DeviceInfo3::notifyDeviceStateChange(int64_t newState) {
if (!mDeviceStateOrientationMap.empty() &&
(mDeviceStateOrientationMap.find(newState) != mDeviceStateOrientationMap.end())) {
mCameraCharacteristics.update(ANDROID_SENSOR_ORIENTATION,
@@ -2464,10 +1682,6 @@
}
}
-status_t CameraProviderManager::ProviderInfo::DeviceInfo3::setTorchMode(bool enabled) {
- return setTorchModeForDevice<InterfaceT>(enabled);
-}
-
status_t CameraProviderManager::ProviderInfo::DeviceInfo3::getCameraInfo(
hardware::CameraInfo *info) const {
if (info == nullptr) return BAD_VALUE;
@@ -2523,21 +1737,6 @@
return isBackwardCompatible;
}
-status_t CameraProviderManager::ProviderInfo::DeviceInfo3::dumpState(int fd) {
- native_handle_t* handle = native_handle_create(1,0);
- handle->data[0] = fd;
- const sp<InterfaceT> interface = startDeviceInterface<InterfaceT>();
- if (interface == nullptr) {
- return DEAD_OBJECT;
- }
- auto ret = interface->dumpState(handle);
- native_handle_delete(handle);
- if (!ret.isOk()) {
- return INVALID_OPERATION;
- }
- return OK;
-}
-
status_t CameraProviderManager::ProviderInfo::DeviceInfo3::getCameraCharacteristics(
bool overrideForPerfClass, CameraMetadata *characteristics) const {
if (characteristics == nullptr) return BAD_VALUE;
@@ -2563,63 +1762,6 @@
return OK;
}
-status_t CameraProviderManager::ProviderInfo::DeviceInfo3::isSessionConfigurationSupported(
- const hardware::camera::device::V3_7::StreamConfiguration &configuration,
- bool *status /*out*/) {
-
- const sp<CameraProviderManager::ProviderInfo::DeviceInfo3::InterfaceT> interface =
- this->startDeviceInterface<CameraProviderManager::ProviderInfo::DeviceInfo3::InterfaceT>();
- if (interface == nullptr) {
- return DEAD_OBJECT;
- }
- 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;
- ::android::hardware::Return<void> ret;
- auto halCb =
- [&callStatus, &status] (Status s, bool combStatus) {
- callStatus = s;
- *status = combStatus;
- };
- if (interface_3_7 != nullptr) {
- ret = interface_3_7->isStreamCombinationSupported_3_7(configuration, halCb);
- } 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, halCb);
- } else {
- return INVALID_OPERATION;
- }
- 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;
-}
-
status_t CameraProviderManager::ProviderInfo::DeviceInfo3::filterSmallJpegSizes() {
int32_t thresholdW = SessionConfigurationUtils::PERF_CLASS_JPEG_THRESH_W;
int32_t thresholdH = SessionConfigurationUtils::PERF_CLASS_JPEG_THRESH_H;
@@ -2871,8 +2013,6 @@
return OK;
}
-
-
CameraProviderManager::ProviderInfo::~ProviderInfo() {
if (mInitialStatusCallbackFuture.valid()) {
mInitialStatusCallbackFuture.wait();
@@ -2881,167 +2021,6 @@
// CameraProvider interface dies, so do not unregister callbacks.
}
-status_t CameraProviderManager::mapToStatusT(const Status& s) {
- switch(s) {
- case Status::OK:
- return OK;
- case Status::ILLEGAL_ARGUMENT:
- return BAD_VALUE;
- case Status::CAMERA_IN_USE:
- return -EBUSY;
- case Status::MAX_CAMERAS_IN_USE:
- return -EUSERS;
- case Status::METHOD_NOT_SUPPORTED:
- return UNKNOWN_TRANSACTION;
- case Status::OPERATION_NOT_SUPPORTED:
- return INVALID_OPERATION;
- case Status::CAMERA_DISCONNECTED:
- return DEAD_OBJECT;
- case Status::INTERNAL_ERROR:
- return INVALID_OPERATION;
- }
- ALOGW("Unexpected HAL status code %d", s);
- return INVALID_OPERATION;
-}
-
-const char* CameraProviderManager::statusToString(const Status& s) {
- switch(s) {
- case Status::OK:
- return "OK";
- case Status::ILLEGAL_ARGUMENT:
- return "ILLEGAL_ARGUMENT";
- case Status::CAMERA_IN_USE:
- return "CAMERA_IN_USE";
- case Status::MAX_CAMERAS_IN_USE:
- return "MAX_CAMERAS_IN_USE";
- case Status::METHOD_NOT_SUPPORTED:
- return "METHOD_NOT_SUPPORTED";
- case Status::OPERATION_NOT_SUPPORTED:
- return "OPERATION_NOT_SUPPORTED";
- case Status::CAMERA_DISCONNECTED:
- return "CAMERA_DISCONNECTED";
- case Status::INTERNAL_ERROR:
- return "INTERNAL_ERROR";
- }
- ALOGW("Unexpected HAL status code %d", s);
- return "UNKNOWN_ERROR";
-}
-
-const char* CameraProviderManager::deviceStatusToString(const CameraDeviceStatus& s) {
- switch(s) {
- case CameraDeviceStatus::NOT_PRESENT:
- return "NOT_PRESENT";
- case CameraDeviceStatus::PRESENT:
- return "PRESENT";
- case CameraDeviceStatus::ENUMERATING:
- return "ENUMERATING";
- }
- ALOGW("Unexpected HAL device status code %d", s);
- return "UNKNOWN_STATUS";
-}
-
-const char* CameraProviderManager::torchStatusToString(const TorchModeStatus& s) {
- switch(s) {
- case TorchModeStatus::NOT_AVAILABLE:
- return "NOT_AVAILABLE";
- case TorchModeStatus::AVAILABLE_OFF:
- return "AVAILABLE_OFF";
- case TorchModeStatus::AVAILABLE_ON:
- return "AVAILABLE_ON";
- }
- ALOGW("Unexpected HAL torch mode status code %d", s);
- return "UNKNOWN_STATUS";
-}
-
-
-status_t HidlVendorTagDescriptor::createDescriptorFromHidl(
- const hardware::hidl_vec<common::V1_0::VendorTagSection>& vts,
- /*out*/
- sp<VendorTagDescriptor>& descriptor) {
-
- int tagCount = 0;
-
- for (size_t s = 0; s < vts.size(); s++) {
- tagCount += vts[s].tags.size();
- }
-
- if (tagCount < 0 || tagCount > INT32_MAX) {
- ALOGE("%s: tag count %d from vendor tag sections is invalid.", __FUNCTION__, tagCount);
- return BAD_VALUE;
- }
-
- Vector<uint32_t> tagArray;
- LOG_ALWAYS_FATAL_IF(tagArray.resize(tagCount) != tagCount,
- "%s: too many (%u) vendor tags defined.", __FUNCTION__, tagCount);
-
-
- sp<HidlVendorTagDescriptor> desc = new HidlVendorTagDescriptor();
- desc->mTagCount = tagCount;
-
- SortedVector<String8> sections;
- KeyedVector<uint32_t, String8> tagToSectionMap;
-
- int idx = 0;
- for (size_t s = 0; s < vts.size(); s++) {
- const common::V1_0::VendorTagSection& section = vts[s];
- const char *sectionName = section.sectionName.c_str();
- if (sectionName == NULL) {
- ALOGE("%s: no section name defined for vendor tag section %zu.", __FUNCTION__, s);
- return BAD_VALUE;
- }
- String8 sectionString(sectionName);
- sections.add(sectionString);
-
- for (size_t j = 0; j < section.tags.size(); j++) {
- uint32_t tag = section.tags[j].tagId;
- if (tag < CAMERA_METADATA_VENDOR_TAG_BOUNDARY) {
- ALOGE("%s: vendor tag %d not in vendor tag section.", __FUNCTION__, tag);
- return BAD_VALUE;
- }
-
- tagArray.editItemAt(idx++) = section.tags[j].tagId;
-
- const char *tagName = section.tags[j].tagName.c_str();
- if (tagName == NULL) {
- ALOGE("%s: no tag name defined for vendor tag %d.", __FUNCTION__, tag);
- return BAD_VALUE;
- }
- desc->mTagToNameMap.add(tag, String8(tagName));
- tagToSectionMap.add(tag, sectionString);
-
- int tagType = (int) section.tags[j].tagType;
- if (tagType < 0 || tagType >= NUM_TYPES) {
- ALOGE("%s: tag type %d from vendor ops does not exist.", __FUNCTION__, tagType);
- return BAD_VALUE;
- }
- desc->mTagToTypeMap.add(tag, tagType);
- }
- }
-
- desc->mSections = sections;
-
- for (size_t i = 0; i < tagArray.size(); ++i) {
- uint32_t tag = tagArray[i];
- String8 sectionString = tagToSectionMap.valueFor(tag);
-
- // Set up tag to section index map
- ssize_t index = sections.indexOf(sectionString);
- LOG_ALWAYS_FATAL_IF(index < 0, "index %zd must be non-negative", index);
- desc->mTagToSectionMap.add(tag, static_cast<uint32_t>(index));
-
- // Set up reverse mapping
- ssize_t reverseIndex = -1;
- if ((reverseIndex = desc->mReverseMapping.indexOfKey(sectionString)) < 0) {
- KeyedVector<String8, uint32_t>* nameMapper = new KeyedVector<String8, uint32_t>();
- reverseIndex = desc->mReverseMapping.add(sectionString, nameMapper);
- }
- desc->mReverseMapping[reverseIndex]->add(desc->mTagToNameMap.valueFor(tag), tag);
- }
-
- descriptor = std::move(desc);
- return OK;
-}
-
// Expects to have mInterfaceMutex locked
std::vector<std::unordered_set<std::string>>
CameraProviderManager::getConcurrentCameraIds() const {
@@ -3055,59 +2034,6 @@
return deviceIdCombinations;
}
-status_t CameraProviderManager::convertToHALStreamCombinationAndCameraIdsLocked(
- const std::vector<CameraIdAndSessionConfiguration> &cameraIdsAndSessionConfigs,
- const std::set<std::string>& perfClassPrimaryCameraIds,
- int targetSdkVersion,
- hardware::hidl_vec<CameraIdAndStreamCombination> *halCameraIdsAndStreamCombinations,
- bool *earlyExit) {
- binder::Status bStatus = binder::Status::ok();
- std::vector<CameraIdAndStreamCombination> halCameraIdsAndStreamsV;
- bool shouldExit = false;
- status_t res = OK;
- for (auto &cameraIdAndSessionConfig : cameraIdsAndSessionConfigs) {
- const std::string& cameraId = cameraIdAndSessionConfig.mCameraId;
- hardware::camera::device::V3_7::StreamConfiguration streamConfiguration;
- CameraMetadata deviceInfo;
- bool overrideForPerfClass =
- SessionConfigurationUtils::targetPerfClassPrimaryCamera(
- perfClassPrimaryCameraIds, cameraId, targetSdkVersion);
- res = getCameraCharacteristicsLocked(cameraId, overrideForPerfClass, &deviceInfo);
- if (res != OK) {
- return res;
- }
- camera3::metadataGetter getMetadata =
- [this](const String8 &id, bool overrideForPerfClass) {
- CameraMetadata physicalDeviceInfo;
- getCameraCharacteristicsLocked(id.string(), overrideForPerfClass,
- &physicalDeviceInfo);
- return physicalDeviceInfo;
- };
- std::vector<std::string> physicalCameraIds;
- isLogicalCameraLocked(cameraId, &physicalCameraIds);
- bStatus =
- SessionConfigurationUtils::convertToHALStreamCombination(
- cameraIdAndSessionConfig.mSessionConfiguration,
- String8(cameraId.c_str()), deviceInfo, getMetadata,
- physicalCameraIds, streamConfiguration,
- overrideForPerfClass, &shouldExit);
- if (!bStatus.isOk()) {
- ALOGE("%s: convertToHALStreamCombination failed", __FUNCTION__);
- return INVALID_OPERATION;
- }
- if (shouldExit) {
- *earlyExit = true;
- return OK;
- }
- CameraIdAndStreamCombination halCameraIdAndStream;
- halCameraIdAndStream.cameraId = cameraId;
- halCameraIdAndStream.streamConfiguration = streamConfiguration;
- halCameraIdsAndStreamsV.push_back(halCameraIdAndStream);
- }
- *halCameraIdsAndStreamCombinations = halCameraIdsAndStreamsV;
- return OK;
-}
-
// Checks if the containing vector of sets has any set that contains all of the
// camera ids in cameraIdsAndSessionConfigs.
static bool checkIfSetContainsAll(
@@ -3142,27 +2068,9 @@
for (auto &provider : mProviders) {
if (checkIfSetContainsAll(cameraIdsAndSessionConfigs,
provider->getConcurrentCameraIdCombinations())) {
- // For each camera device in cameraIdsAndSessionConfigs collect
- // the streamConfigs and create the HAL
- // CameraIdAndStreamCombination, exit early if needed
- hardware::hidl_vec<CameraIdAndStreamCombination> halCameraIdsAndStreamCombinations;
- bool knowUnsupported = false;
- status_t res = convertToHALStreamCombinationAndCameraIdsLocked(
- cameraIdsAndSessionConfigs, perfClassPrimaryCameraIds,
- targetSdkVersion, &halCameraIdsAndStreamCombinations, &knowUnsupported);
- if (res != OK) {
- ALOGE("%s unable to convert session configurations provided to HAL stream"
- "combinations", __FUNCTION__);
- return res;
- }
- if (knowUnsupported) {
- // We got to know the streams aren't valid before doing the HAL
- // call itself.
- *isSupported = false;
- return OK;
- }
return provider->isConcurrentSessionConfigurationSupported(
- halCameraIdsAndStreamCombinations, isSupported);
+ cameraIdsAndSessionConfigs, perfClassPrimaryCameraIds, targetSdkVersion,
+ isSupported);
}
}
*isSupported = false;
@@ -3172,7 +2080,7 @@
status_t CameraProviderManager::getCameraCharacteristicsLocked(const std::string &id,
bool overrideForPerfClass, CameraMetadata* characteristics) const {
- auto deviceInfo = findDeviceInfoLocked(id, /*minVersion*/ {3,0}, /*maxVersion*/ {5,0});
+ auto deviceInfo = findDeviceInfoLocked(id, /*minVersion*/ {3, 0}, /*maxVersion*/ {5, 0});
if (deviceInfo != nullptr) {
return deviceInfo->getCameraCharacteristics(overrideForPerfClass, characteristics);
}
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index f28d128..64f5abf 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -29,34 +29,40 @@
#include <camera/CameraParameters2.h>
#include <camera/CameraMetadata.h>
#include <camera/CameraBase.h>
+#include <utils/Condition.h>
#include <utils/Errors.h>
+#include <android/hardware/ICameraService.h>
+#include <utils/IPCTransport.h>
#include <android/hardware/camera/common/1.0/types.h>
#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/provider/2.7/ICameraProvider.h>
#include <android/hardware/camera/device/3.7/types.h>
+#include <android/hardware/camera/device/3.8/types.h>
#include <android/hidl/manager/1.0/IServiceNotification.h>
+#include <binder/IServiceManager.h>
#include <camera/VendorTagDescriptor.h>
namespace android {
-/**
- * The vendor tag descriptor class that takes HIDL vendor tag information as
- * input. Not part of VendorTagDescriptor class because that class is used
- * in AIDL generated sources which don't have access to HIDL headers.
- */
-class HidlVendorTagDescriptor : public VendorTagDescriptor {
-public:
- /**
- * Create a VendorTagDescriptor object from the HIDL VendorTagSection
- * vector.
- *
- * Returns OK on success, or a negative error code.
- */
- static status_t createDescriptorFromHidl(
- const hardware::hidl_vec<hardware::camera::common::V1_0::VendorTagSection>& vts,
- /*out*/
- sp<VendorTagDescriptor>& descriptor);
+
+using hardware::camera2::utils::CameraIdAndSessionConfiguration;
+
+enum class CameraDeviceStatus : uint32_t {
+ NOT_PRESENT = 0,
+ PRESENT = 1,
+ ENUMERATING = 2
+};
+
+enum class TorchModeStatus : uint32_t {
+ NOT_AVAILABLE = 0,
+ AVAILABLE_OFF = 1,
+ AVAILABLE_ON = 2
+};
+
+struct CameraResourceCost {
+ uint32_t resourceCost;
+ std::vector<std::string> conflictingDevices;
};
enum SystemCameraKind {
@@ -102,12 +108,14 @@
*/
class CameraProviderManager : virtual public hidl::manager::V1_0::IServiceNotification {
public:
-
+ // needs to be made friend strict since HidlProviderInfo needs to inherit
+ // from CameraProviderManager::ProviderInfo which isn't a public member.
+ friend struct HidlProviderInfo;
~CameraProviderManager();
// Tiny proxy for the static methods in a HIDL interface that communicate with the hardware
// service manager, to be replacable in unit tests with a fake.
- struct ServiceInteractionProxy {
+ struct HidlServiceInteractionProxy {
virtual bool registerForNotifications(
const std::string &serviceName,
const sp<hidl::manager::V1_0::IServiceNotification>
@@ -119,12 +127,12 @@
virtual sp<hardware::camera::provider::V2_4::ICameraProvider> getService(
const std::string &serviceName) = 0;
virtual hardware::hidl_vec<hardware::hidl_string> listServices() = 0;
- virtual ~ServiceInteractionProxy() {}
+ virtual ~HidlServiceInteractionProxy() {}
};
// Standard use case - call into the normal generated static methods which invoke
// the real hardware service manager
- struct HardwareServiceInteractionProxy : public ServiceInteractionProxy {
+ struct HidlServiceInteractionProxyImpl : public HidlServiceInteractionProxy {
virtual bool registerForNotifications(
const std::string &serviceName,
const sp<hidl::manager::V1_0::IServiceNotification>
@@ -151,15 +159,15 @@
~StatusListener() {}
virtual void onDeviceStatusChanged(const String8 &cameraId,
- hardware::camera::common::V1_0::CameraDeviceStatus newStatus) = 0;
+ CameraDeviceStatus newStatus) = 0;
virtual void onDeviceStatusChanged(const String8 &cameraId,
const String8 &physicalCameraId,
- hardware::camera::common::V1_0::CameraDeviceStatus newStatus) = 0;
+ CameraDeviceStatus newStatus) = 0;
virtual void onTorchStatusChanged(const String8 &cameraId,
- hardware::camera::common::V1_0::TorchModeStatus newStatus,
+ TorchModeStatus newStatus,
SystemCameraKind kind) = 0;
virtual void onTorchStatusChanged(const String8 &cameraId,
- hardware::camera::common::V1_0::TorchModeStatus newStatus) = 0;
+ TorchModeStatus newStatus) = 0;
virtual void onNewProviderRegistered() = 0;
};
@@ -179,7 +187,10 @@
* used for testing. The lifetime of the proxy must exceed the lifetime of the manager.
*/
status_t initialize(wp<StatusListener> listener,
- ServiceInteractionProxy *proxy = &sHardwareServiceInteractionProxy);
+ HidlServiceInteractionProxy *hidlProxy = &sHidlServiceInteractionProxy);
+
+ status_t getCameraIdIPCTransport(const std::string &id,
+ IPCTransport *providerTransport) const;
/**
* Retrieve the total number of available cameras.
@@ -217,7 +228,7 @@
* Return the resource cost of this camera device
*/
status_t getResourceCost(const std::string &id,
- hardware::camera::common::V1_0::CameraResourceCost* cost) const;
+ CameraResourceCost* cost) const;
/**
* Return the old camera API camera info
@@ -243,7 +254,8 @@
* Check for device support of specific stream combination.
*/
status_t isSessionConfigurationSupported(const std::string& id,
- const hardware::camera::device::V3_7::StreamConfiguration &configuration,
+ const SessionConfiguration &configuration,
+ bool overrideForPerfClass,
bool *status /*out*/) const;
/**
@@ -258,6 +270,17 @@
bool supportSetTorchMode(const std::string &id) const;
/**
+ * Check if torch strength update should be skipped or not.
+ */
+ bool shouldSkipTorchStrengthUpdate(const std::string &id, int32_t torchStrength) const;
+
+ /**
+ * Return the default torch strength level if the torch strength control
+ * feature is supported.
+ */
+ int32_t getTorchDefaultStrengthLevel(const std::string &id) const;
+
+ /**
* Turn on or off the flashlight on a given camera device.
* May fail if the device does not support this API, is in active use, or if the device
* doesn't exist, etc.
@@ -265,6 +288,24 @@
status_t setTorchMode(const std::string &id, bool enabled);
/**
+ * Change the brightness level of the flash unit associated with the cameraId and
+ * set it to the value in torchStrength.
+ * If the torch is OFF and torchStrength > 0, the torch will be turned ON with the
+ * specified strength level. If the torch is ON, only the brightness level will be
+ * changed.
+ *
+ * This operation will fail if the device does not have flash unit, has flash unit
+ * but does not support this API, torchStrength is invalid or if the device doesn't
+ * exist etc.
+ */
+ status_t turnOnTorchWithStrengthLevel(const std::string &id, int32_t torchStrength);
+
+ /**
+ * Return the torch strength level of this camera device.
+ */
+ status_t getTorchStrengthLevel(const std::string &id, int32_t* torchStrength);
+
+ /**
* Setup vendor tags for all registered providers
*/
status_t setUpVendorTags();
@@ -272,8 +313,7 @@
/**
* Inform registered providers about a device state change, such as folding or unfolding
*/
- status_t notifyDeviceStateChange(
- android::hardware::hidl_bitfield<hardware::camera::provider::V2_5::DeviceState> newState);
+ status_t notifyDeviceStateChange(int64_t newState);
/**
* Open an active session to a camera device.
@@ -281,7 +321,7 @@
* This fully powers on the camera device hardware, and returns a handle to a
* session to be used for hardware configuration and operation.
*/
- status_t openSession(const std::string &id,
+ status_t openHidlSession(const std::string &id,
const sp<hardware::camera::device::V3_2::ICameraDeviceCallback>& callback,
/*out*/
sp<hardware::camera::device::V3_2::ICameraDeviceSession> *session);
@@ -328,41 +368,56 @@
status_t filterSmallJpegSizes(const std::string& cameraId);
+ status_t notifyUsbDeviceEvent(int32_t eventId, const std::string &usbDeviceId);
+
static const float kDepthARTolerance;
private:
// All private members, unless otherwise noted, expect mInterfaceMutex to be locked before use
mutable std::mutex mInterfaceMutex;
wp<StatusListener> mListener;
- ServiceInteractionProxy* mServiceProxy;
+ HidlServiceInteractionProxy* mHidlServiceProxy;
// Current overall Android device physical status
- android::hardware::hidl_bitfield<hardware::camera::provider::V2_5::DeviceState> mDeviceState;
+ int64_t mDeviceState;
// mProviderLifecycleLock is locked during onRegistration and removeProvider
mutable std::mutex mProviderLifecycleLock;
- static HardwareServiceInteractionProxy sHardwareServiceInteractionProxy;
+ static HidlServiceInteractionProxyImpl sHidlServiceInteractionProxy;
+
+ struct HalCameraProvider {
+ // Empty parent struct for storing either aidl / hidl camera provider reference
+ HalCameraProvider(const char *descriptor) : mDescriptor(descriptor) { };
+ virtual ~HalCameraProvider() {};
+ std::string mDescriptor;
+ };
+
+ struct HidlHalCameraProvider : public HalCameraProvider {
+ HidlHalCameraProvider(
+ const sp<hardware::camera::provider::V2_4::ICameraProvider> &provider,
+ const char *descriptor) :
+ HalCameraProvider(descriptor), mCameraProvider(provider) { };
+ private:
+ sp<hardware::camera::provider::V2_4::ICameraProvider> mCameraProvider;
+ };
// Mapping from CameraDevice IDs to CameraProviders. This map is used to keep the
// ICameraProvider alive while it is in use by the camera with the given ID for camera
// capabilities
- std::unordered_map<std::string, sp<hardware::camera::provider::V2_4::ICameraProvider>>
+ std::unordered_map<std::string, std::shared_ptr<HalCameraProvider>>
mCameraProviderByCameraId;
// Mapping from CameraDevice IDs to CameraProviders. This map is used to keep the
// ICameraProvider alive while it is in use by the camera with the given ID for torch
// capabilities
- std::unordered_map<std::string, sp<hardware::camera::provider::V2_4::ICameraProvider>>
+ std::unordered_map<std::string, std::shared_ptr<HalCameraProvider>>
mTorchProviderByCameraId;
// Lock for accessing mCameraProviderByCameraId and mTorchProviderByCameraId
std::mutex mProviderInterfaceMapLock;
-
- struct ProviderInfo :
- virtual public hardware::camera::provider::V2_6::ICameraProviderCallback,
- virtual public hardware::hidl_death_recipient
- {
+ struct ProviderInfo : public virtual RefBase {
+ friend struct HidlProviderInfo;
const std::string mProviderName;
const std::string mProviderInstance;
const metadata_vendor_id_t mProviderTagid;
@@ -371,61 +426,20 @@
bool mSetTorchModeSupported;
bool mIsRemote;
- // Current overall Android device physical status
- hardware::hidl_bitfield<hardware::camera::provider::V2_5::DeviceState> mDeviceState;
-
- // This pointer is used to keep a reference to the ICameraProvider that was last accessed.
- wp<hardware::camera::provider::V2_4::ICameraProvider> mActiveInterface;
-
- sp<hardware::camera::provider::V2_4::ICameraProvider> mSavedInterface;
-
ProviderInfo(const std::string &providerName, const std::string &providerInstance,
CameraProviderManager *manager);
~ProviderInfo();
- status_t initialize(sp<hardware::camera::provider::V2_4::ICameraProvider>& interface,
- hardware::hidl_bitfield<hardware::camera::provider::V2_5::DeviceState>
- currentDeviceState);
-
- const sp<hardware::camera::provider::V2_4::ICameraProvider> startProviderInterface();
+ virtual IPCTransport getIPCTransport() = 0;
const std::string& getType() const;
- status_t addDevice(const std::string& name,
- hardware::camera::common::V1_0::CameraDeviceStatus initialStatus =
- hardware::camera::common::V1_0::CameraDeviceStatus::PRESENT,
- /*out*/ std::string *parsedId = nullptr);
-
status_t dump(int fd, const Vector<String16>& args) const;
- // ICameraProviderCallbacks interface - these lock the parent mInterfaceMutex
- hardware::Return<void> cameraDeviceStatusChange(
- const hardware::hidl_string& cameraDeviceName,
- hardware::camera::common::V1_0::CameraDeviceStatus newStatus) override;
- hardware::Return<void> torchModeStatusChange(
- const hardware::hidl_string& cameraDeviceName,
- hardware::camera::common::V1_0::TorchModeStatus newStatus) override;
- hardware::Return<void> physicalCameraDeviceStatusChange(
- const hardware::hidl_string& cameraDeviceName,
- const hardware::hidl_string& physicalCameraDeviceName,
- hardware::camera::common::V1_0::CameraDeviceStatus newStatus) override;
-
- status_t cameraDeviceStatusChangeLocked(
- std::string* id, const hardware::hidl_string& cameraDeviceName,
- hardware::camera::common::V1_0::CameraDeviceStatus newStatus);
- status_t physicalCameraDeviceStatusChangeLocked(
- std::string* id, std::string* physicalId,
- const hardware::hidl_string& cameraDeviceName,
- const hardware::hidl_string& physicalCameraDeviceName,
- hardware::camera::common::V1_0::CameraDeviceStatus newStatus);
-
- // hidl_death_recipient interface - this locks the parent mInterfaceMutex
- virtual void serviceDied(uint64_t cookie, const wp<hidl::base::V1_0::IBase>& who) override;
-
/**
* Setup vendor tags for this provider
*/
- status_t setUpVendorTags();
+ virtual status_t setUpVendorTags() = 0;
/**
* Notify provider about top-level device physical state changes
@@ -434,9 +448,9 @@
* It is possible for camera providers to add/remove devices and try to
* acquire it.
*/
- status_t notifyDeviceStateChange(
- hardware::hidl_bitfield<hardware::camera::provider::V2_5::DeviceState>
- newDeviceState);
+ virtual status_t notifyDeviceStateChange(int64_t newDeviceState) = 0;
+
+ virtual bool successfullyStartedProviderInterface() = 0;
std::vector<std::unordered_set<std::string>> getConcurrentCameraIdCombinations();
@@ -445,40 +459,63 @@
*
* Note that 'mInterfaceMutex' should be held when calling this method.
*/
- void notifyDeviceInfoStateChangeLocked(
- hardware::hidl_bitfield<hardware::camera::provider::V2_5::DeviceState>
- newDeviceState);
+ void notifyDeviceInfoStateChangeLocked(int64_t newDeviceState);
/**
* Query the camera provider for concurrent stream configuration support
*/
- status_t isConcurrentSessionConfigurationSupported(
- const hardware::hidl_vec<
- hardware::camera::provider::V2_7::CameraIdAndStreamCombination>
- &halCameraIdsAndStreamCombinations,
- bool *isSupported);
+ virtual status_t isConcurrentSessionConfigurationSupported(
+ const std::vector<CameraIdAndSessionConfiguration> &cameraIdsAndSessionConfigs,
+ const std::set<std::string>& perfClassPrimaryCameraIds,
+ int targetSdkVersion, bool *isSupported) = 0;
+
+
+ /**
+ * Remove all devices associated with this provider and notify listeners
+ * with NOT_PRESENT state.
+ */
+ void removeAllDevices();
+
+ /**
+ * Provider is an external lazy HAL
+ */
+ bool isExternalLazyHAL() const;
// Basic device information, common to all camera devices
struct DeviceInfo {
const std::string mName; // Full instance name
const std::string mId; // ID section of full name
+ //Both hidl and aidl DeviceInfos. Aidl deviceInfos get {3, 8} to
+ //start off.
const hardware::hidl_version mVersion;
const metadata_vendor_id_t mProviderTagid;
bool mIsLogicalCamera;
std::vector<std::string> mPhysicalIds;
hardware::CameraInfo mInfo;
- sp<IBase> mSavedInterface;
SystemCameraKind mSystemCameraKind = SystemCameraKind::PUBLIC;
- const hardware::camera::common::V1_0::CameraResourceCost mResourceCost;
+ const CameraResourceCost mResourceCost;
- hardware::camera::common::V1_0::CameraDeviceStatus mStatus;
+ CameraDeviceStatus mStatus;
wp<ProviderInfo> mParentProvider;
+ // Torch strength default, maximum levels if the torch strength control
+ // feature is supported.
+ int32_t mTorchStrengthLevel;
+ int32_t mTorchMaximumStrengthLevel;
+ int32_t mTorchDefaultStrengthLevel;
+
+ // Wait for lazy HALs to confirm device availability
+ static const nsecs_t kDeviceAvailableTimeout = 2000e6; // 2000 ms
+ Mutex mDeviceAvailableLock;
+ Condition mDeviceAvailableSignal;
+ bool mIsDeviceAvailable = true;
bool hasFlashUnit() const { return mHasFlashUnit; }
bool supportNativeZoomRatio() const { return mSupportNativeZoomRatio; }
virtual status_t setTorchMode(bool enabled) = 0;
+ virtual status_t turnOnTorchWithStrengthLevel(int32_t torchStrength) = 0;
+ virtual status_t getTorchStrengthLevel(int32_t *torchStrength) = 0;
virtual status_t getCameraInfo(hardware::CameraInfo *info) const = 0;
virtual bool isAPI1Compatible() const = 0;
virtual status_t dumpState(int fd) = 0;
@@ -496,44 +533,32 @@
}
virtual status_t isSessionConfigurationSupported(
- const hardware::camera::device::V3_7::StreamConfiguration &/*configuration*/,
+ const SessionConfiguration &/*configuration*/,
+ bool /*overrideForPerfClass*/,
bool * /*status*/) {
return INVALID_OPERATION;
}
virtual status_t filterSmallJpegSizes() = 0;
- virtual void notifyDeviceStateChange(
- hardware::hidl_bitfield<hardware::camera::provider::V2_5::DeviceState>
- /*newState*/) {}
-
- template<class InterfaceT>
- sp<InterfaceT> startDeviceInterface();
+ virtual void notifyDeviceStateChange(int64_t /*newState*/) {}
DeviceInfo(const std::string& name, const metadata_vendor_id_t tagId,
const std::string &id, const hardware::hidl_version& version,
const std::vector<std::string>& publicCameraIds,
- const hardware::camera::common::V1_0::CameraResourceCost& resourceCost,
+ const CameraResourceCost& resourceCost,
sp<ProviderInfo> parentProvider) :
mName(name), mId(id), mVersion(version), mProviderTagid(tagId),
mIsLogicalCamera(false), mResourceCost(resourceCost),
- mStatus(hardware::camera::common::V1_0::CameraDeviceStatus::PRESENT),
- mParentProvider(parentProvider), mHasFlashUnit(false),
- mSupportNativeZoomRatio(false), mPublicCameraIds(publicCameraIds) {}
- virtual ~DeviceInfo();
+ mStatus(CameraDeviceStatus::PRESENT),
+ mParentProvider(parentProvider), mTorchStrengthLevel(0),
+ mTorchMaximumStrengthLevel(0), mTorchDefaultStrengthLevel(0),
+ mHasFlashUnit(false), mSupportNativeZoomRatio(false),
+ mPublicCameraIds(publicCameraIds) {}
+ virtual ~DeviceInfo() {}
protected:
+
bool mHasFlashUnit; // const after constructor
bool mSupportNativeZoomRatio; // const after constructor
const std::vector<std::string>& mPublicCameraIds;
-
- template<class InterfaceT>
- static status_t setTorchMode(InterfaceT& interface, bool enabled);
-
- template<class InterfaceT>
- status_t setTorchModeForDevice(bool enabled) {
- // Don't save the ICameraProvider interface here because we assume that this was
- // called from CameraProviderManager::setTorchMode(), which does save it.
- const sp<InterfaceT> interface = startDeviceInterface<InterfaceT>();
- return DeviceInfo::setTorchMode(interface, enabled);
- }
};
std::vector<std::unique_ptr<DeviceInfo>> mDevices;
std::unordered_set<std::string> mUniqueCameraIds;
@@ -548,33 +573,33 @@
// HALv3-specific camera fields, including the actual device interface
struct DeviceInfo3 : public DeviceInfo {
- typedef hardware::camera::device::V3_2::ICameraDevice InterfaceT;
- virtual status_t setTorchMode(bool enabled) override;
+ virtual status_t setTorchMode(bool enabled) = 0;
+ virtual status_t turnOnTorchWithStrengthLevel(int32_t torchStrength) = 0;
+ virtual status_t getTorchStrengthLevel(int32_t *torchStrength) = 0;
virtual status_t getCameraInfo(hardware::CameraInfo *info) const override;
virtual bool isAPI1Compatible() const override;
- virtual status_t dumpState(int fd) override;
+ virtual status_t dumpState(int fd) = 0;
virtual status_t getCameraCharacteristics(
bool overrideForPerfClass,
CameraMetadata *characteristics) const override;
virtual status_t getPhysicalCameraCharacteristics(const std::string& physicalCameraId,
CameraMetadata *characteristics) const override;
virtual status_t isSessionConfigurationSupported(
- const hardware::camera::device::V3_7::StreamConfiguration &configuration,
- bool *status /*out*/)
- override;
+ const SessionConfiguration &configuration, bool /*overrideForPerfClass*/,
+ bool *status /*out*/) = 0;
virtual status_t filterSmallJpegSizes() override;
virtual void notifyDeviceStateChange(
- hardware::hidl_bitfield<hardware::camera::provider::V2_5::DeviceState>
- newState) override;
+ int64_t newState) override;
DeviceInfo3(const std::string& name, const metadata_vendor_id_t tagId,
const std::string &id, uint16_t minorVersion,
- const hardware::camera::common::V1_0::CameraResourceCost& resourceCost,
+ const CameraResourceCost& resourceCost,
sp<ProviderInfo> parentProvider,
- const std::vector<std::string>& publicCameraIds, sp<InterfaceT> interface);
- virtual ~DeviceInfo3();
- private:
+ const std::vector<std::string>& publicCameraIds);
+ virtual ~DeviceInfo3() {};
+ protected:
+ // Modified by derived transport specific (hidl / aidl) class
CameraMetadata mCameraCharacteristics;
// Map device states to sensor orientations
std::unordered_map<int64_t, int32_t> mDeviceStateOrientationMap;
@@ -614,8 +639,7 @@
const camera_metadata_entry& halStreamConfigs,
const camera_metadata_entry& halStreamDurations);
};
-
- private:
+ protected:
std::string mType;
uint32_t mId;
@@ -625,12 +649,12 @@
struct CameraStatusInfoT {
bool isPhysicalCameraStatus = false;
- hardware::hidl_string cameraId;
- hardware::hidl_string physicalCameraId;
- hardware::camera::common::V1_0::CameraDeviceStatus status;
- CameraStatusInfoT(bool isForPhysicalCamera, const hardware::hidl_string& id,
- const hardware::hidl_string& physicalId,
- hardware::camera::common::V1_0::CameraDeviceStatus s) :
+ std::string cameraId;
+ std::string physicalCameraId;
+ CameraDeviceStatus status;
+ CameraStatusInfoT(bool isForPhysicalCamera, const std::string& id,
+ const std::string& physicalId,
+ CameraDeviceStatus s) :
isPhysicalCameraStatus(isForPhysicalCamera), cameraId(id),
physicalCameraId(physicalId), status(s) {}
};
@@ -647,17 +671,6 @@
std::vector<std::unordered_set<std::string>> mConcurrentCameraIdCombinations;
- // Templated method to instantiate the right kind of DeviceInfo and call the
- // right CameraProvider getCameraDeviceInterface_* method.
- template<class DeviceInfoT>
- std::unique_ptr<DeviceInfo> initializeDeviceInfo(const std::string &name,
- const metadata_vendor_id_t tagId, const std::string &id,
- uint16_t minorVersion);
-
- // Helper for initializeDeviceInfo to use the right CameraProvider get method.
- template<class InterfaceT>
- sp<InterfaceT> startDeviceInterface(const std::string &name);
-
// Parse provider instance name for type and id
static status_t parseProviderName(const std::string& name,
std::string *type, uint32_t *id);
@@ -671,18 +684,13 @@
void removeDevice(std::string id);
- // Expects to have mLock locked
- status_t reCacheConcurrentStreamingCameraIdsLocked();
- // Expects to have mLock locked
- status_t getConcurrentCameraIdsInternalLocked(
- sp<hardware::camera::provider::V2_6::ICameraProvider> &interface2_6);
};
/**
* Save the ICameraProvider while it is being used by a camera or torch client
*/
void saveRef(DeviceMode usageType, const std::string &cameraId,
- sp<hardware::camera::provider::V2_4::ICameraProvider> provider);
+ std::shared_ptr<HalCameraProvider> provider);
// Utility to find a DeviceInfo by ID; pointer is only valid while mInterfaceMutex is held
// and the calling code doesn't mutate the list of providers or their lists of devices.
@@ -693,9 +701,15 @@
hardware::hidl_version minVersion = hardware::hidl_version{0,0},
hardware::hidl_version maxVersion = hardware::hidl_version{1000,0}) const;
- status_t addProviderLocked(const std::string& newProvider, bool preexisting = false);
+ // Map external providers to USB devices in order to handle USB hotplug
+ // events for lazy HALs
+ std::pair<std::vector<std::string>, sp<ProviderInfo>>
+ mExternalUsbDevicesForProvider;
+ sp<ProviderInfo> startExternalLazyProvider() const;
- status_t tryToInitializeProviderLocked(const std::string& providerName,
+ status_t addHidlProviderLocked(const std::string& newProvider, bool preexisting = false);
+
+ status_t tryToInitializeHidlProviderLocked(const std::string& providerName,
const sp<ProviderInfo>& providerInfo);
bool isLogicalCameraLocked(const std::string& id, std::vector<std::string>* physicalCameraIds);
@@ -708,14 +722,6 @@
size_t mProviderInstanceId = 0;
std::vector<sp<ProviderInfo>> mProviders;
- void addProviderToMap(
- const std::string &cameraId,
- sp<hardware::camera::provider::V2_4::ICameraProvider> provider,
- bool isTorchUsage);
- void removeCameraIdFromMap(
- std::unordered_map<std::string, sp<hardware::camera::provider::V2_4::ICameraProvider>> &map,
- const std::string &cameraId);
-
static const char* deviceStatusToString(
const hardware::camera::common::V1_0::CameraDeviceStatus&);
static const char* torchStatusToString(
@@ -726,20 +732,14 @@
void filterLogicalCameraIdsLocked(std::vector<std::string>& deviceIds) const;
status_t getSystemCameraKindLocked(const std::string& id, SystemCameraKind *kind) const;
- std::pair<bool, ProviderInfo::DeviceInfo *> isHiddenPhysicalCameraInternal(const std::string& cameraId) const;
+ std::pair<bool, ProviderInfo::DeviceInfo *> isHiddenPhysicalCameraInternal(
+ const std::string& cameraId) const;
void collectDeviceIdsLocked(const std::vector<std::string> deviceIds,
std::vector<std::string>& normalDeviceIds,
std::vector<std::string>& systemCameraDeviceIds) const;
- status_t convertToHALStreamCombinationAndCameraIdsLocked(
- const std::vector<hardware::camera2::utils::CameraIdAndSessionConfiguration>
- &cameraIdsAndSessionConfigs,
- const std::set<std::string>& perfClassPrimaryCameraIds,
- int targetSdkVersion,
- hardware::hidl_vec<hardware::camera::provider::V2_7::CameraIdAndStreamCombination>
- *halCameraIdsAndStreamCombinations,
- bool *earlyExit);
+ status_t usbDeviceDetached(const std::string &usbDeviceId);
};
} // namespace android
diff --git a/services/camera/libcameraservice/common/DepthPhotoProcessor.cpp b/services/camera/libcameraservice/common/DepthPhotoProcessor.cpp
index c995670..719ff2c 100644
--- a/services/camera/libcameraservice/common/DepthPhotoProcessor.cpp
+++ b/services/camera/libcameraservice/common/DepthPhotoProcessor.cpp
@@ -42,6 +42,10 @@
#include <xmpmeta/xmp_data.h>
#include <xmpmeta/xmp_writer.h>
+#ifndef __unused
+#define __unused __attribute__((__unused__))
+#endif
+
using dynamic_depth::Camera;
using dynamic_depth::Cameras;
using dynamic_depth::CameraParams;
diff --git a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
new file mode 100644
index 0000000..e8432a6
--- /dev/null
+++ b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
@@ -0,0 +1,1564 @@
+/*
+ * Copyright (C) 2022 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 "HidlProviderInfo.h"
+
+#include <cutils/properties.h>
+
+#include <android/hardware/ICameraService.h>
+#include <camera_metadata_hidden.h>
+
+#include "device3/ZoomRatioMapper.h"
+#include <utils/SessionConfigurationUtils.h>
+#include <utils/Trace.h>
+
+#include <android/hardware/camera/device/3.7/ICameraDevice.h>
+#include <android/hardware/camera/device/3.8/ICameraDevice.h>
+
+namespace {
+const bool kEnableLazyHal(property_get_bool("ro.camera.enableLazyHal", false));
+} // anonymous namespace
+
+namespace android {
+
+using namespace android::camera3;
+using namespace hardware::camera;
+using hardware::camera::common::V1_0::VendorTagSection;
+using hardware::camera::common::V1_0::Status;
+using hardware::camera::provider::V2_7::CameraIdAndStreamCombination;
+using hardware::camera2::utils::CameraIdAndSessionConfiguration;
+
+
+using StatusListener = CameraProviderManager::StatusListener;
+
+using hardware::camera::provider::V2_5::DeviceState;
+using hardware::ICameraService;
+
+status_t HidlProviderInfo::mapToStatusT(const Status& s) {
+ switch(s) {
+ case Status::OK:
+ return OK;
+ case Status::ILLEGAL_ARGUMENT:
+ return BAD_VALUE;
+ case Status::CAMERA_IN_USE:
+ return -EBUSY;
+ case Status::MAX_CAMERAS_IN_USE:
+ return -EUSERS;
+ case Status::METHOD_NOT_SUPPORTED:
+ return UNKNOWN_TRANSACTION;
+ case Status::OPERATION_NOT_SUPPORTED:
+ return INVALID_OPERATION;
+ case Status::CAMERA_DISCONNECTED:
+ return DEAD_OBJECT;
+ case Status::INTERNAL_ERROR:
+ return INVALID_OPERATION;
+ }
+ ALOGW("Unexpected HAL status code %d", s);
+ return INVALID_OPERATION;
+}
+
+static hardware::hidl_bitfield<DeviceState> mapToHidlDeviceState(int64_t newState) {
+ hardware::hidl_bitfield<DeviceState> newDeviceState{};
+ if (newState & ICameraService::DEVICE_STATE_BACK_COVERED) {
+ newDeviceState |= DeviceState::BACK_COVERED;
+ }
+ if (newState & ICameraService::DEVICE_STATE_FRONT_COVERED) {
+ newDeviceState |= DeviceState::FRONT_COVERED;
+ }
+ if (newState & ICameraService::DEVICE_STATE_FOLDED) {
+ newDeviceState |= DeviceState::FOLDED;
+ }
+ // Only map vendor bits directly
+ uint64_t vendorBits = static_cast<uint64_t>(newState) & 0xFFFFFFFF00000000l;
+ newDeviceState |= vendorBits;
+
+ ALOGV("%s: New device state 0x%" PRIx64, __FUNCTION__, newDeviceState);
+ return newDeviceState;
+}
+
+const char* statusToString(const Status& s) {
+ switch(s) {
+ case Status::OK:
+ return "OK";
+ case Status::ILLEGAL_ARGUMENT:
+ return "ILLEGAL_ARGUMENT";
+ case Status::CAMERA_IN_USE:
+ return "CAMERA_IN_USE";
+ case Status::MAX_CAMERAS_IN_USE:
+ return "MAX_CAMERAS_IN_USE";
+ case Status::METHOD_NOT_SUPPORTED:
+ return "METHOD_NOT_SUPPORTED";
+ case Status::OPERATION_NOT_SUPPORTED:
+ return "OPERATION_NOT_SUPPORTED";
+ case Status::CAMERA_DISCONNECTED:
+ return "CAMERA_DISCONNECTED";
+ case Status::INTERNAL_ERROR:
+ return "INTERNAL_ERROR";
+ }
+ ALOGW("Unexpected HAL status code %d", s);
+ return "UNKNOWN_ERROR";
+}
+
+static common::V1_0::CameraDeviceStatus mapToHidlCameraDeviceStatus(const CameraDeviceStatus& s) {
+ switch(s) {
+ case CameraDeviceStatus::PRESENT:
+ return common::V1_0::CameraDeviceStatus::PRESENT;
+ case CameraDeviceStatus::NOT_PRESENT:
+ return common::V1_0::CameraDeviceStatus::NOT_PRESENT;
+ case CameraDeviceStatus::ENUMERATING:
+ return common::V1_0::CameraDeviceStatus::ENUMERATING;
+ }
+ ALOGW("Unexpectedcamera device status code %d", s);
+ return common::V1_0::CameraDeviceStatus::NOT_PRESENT;
+}
+
+static CameraDeviceStatus hidlToInternalCameraDeviceStatus(
+ const common::V1_0::CameraDeviceStatus& s) {
+ switch(s) {
+ case common::V1_0::CameraDeviceStatus::PRESENT:
+ return CameraDeviceStatus::PRESENT;
+ case common::V1_0::CameraDeviceStatus::NOT_PRESENT:
+ return CameraDeviceStatus::NOT_PRESENT;
+ case common::V1_0::CameraDeviceStatus::ENUMERATING:
+ return CameraDeviceStatus::ENUMERATING;
+ }
+ ALOGW("Unexpectedcamera device status code %d", s);
+ return CameraDeviceStatus::NOT_PRESENT;
+}
+
+static TorchModeStatus hidlToInternalTorchModeStatus(
+ const common::V1_0::TorchModeStatus& s) {
+ switch(s) {
+ case common::V1_0::TorchModeStatus::NOT_AVAILABLE:
+ return TorchModeStatus::NOT_AVAILABLE;
+ case common::V1_0::TorchModeStatus::AVAILABLE_OFF:
+ return TorchModeStatus::AVAILABLE_OFF;
+ case common::V1_0::TorchModeStatus::AVAILABLE_ON:
+ return TorchModeStatus::AVAILABLE_ON;
+ }
+ ALOGW("Unexpectedcamera torch mode status code %d", s);
+ return TorchModeStatus::NOT_AVAILABLE;
+}
+
+static CameraResourceCost hidlToInternalResourceCost(
+ const common::V1_0::CameraResourceCost& s) {
+ CameraResourceCost internalResourceCost;
+ internalResourceCost.resourceCost = s.resourceCost;
+ for (const auto device : s.conflictingDevices) {
+ internalResourceCost.conflictingDevices.emplace_back(device.c_str());
+ }
+ return internalResourceCost;
+}
+
+static const char* deviceStatusToString(const common::V1_0::CameraDeviceStatus& s) {
+ switch(s) {
+ case common::V1_0::CameraDeviceStatus::NOT_PRESENT:
+ return "NOT_PRESENT";
+ case common::V1_0::CameraDeviceStatus::PRESENT:
+ return "PRESENT";
+ case common::V1_0::CameraDeviceStatus::ENUMERATING:
+ return "ENUMERATING";
+ }
+ ALOGW("Unexpected HAL device status code %d", s);
+ return "UNKNOWN_STATUS";
+}
+
+static const char* torchStatusToString(const common::V1_0::TorchModeStatus& s) {
+ switch(s) {
+ case common::V1_0::TorchModeStatus::NOT_AVAILABLE:
+ return "NOT_AVAILABLE";
+ case common::V1_0::TorchModeStatus::AVAILABLE_OFF:
+ return "AVAILABLE_OFF";
+ case common::V1_0::TorchModeStatus::AVAILABLE_ON:
+ return "AVAILABLE_ON";
+ }
+ ALOGW("Unexpected HAL torch mode status code %d", s);
+ return "UNKNOWN_STATUS";
+}
+
+status_t HidlProviderInfo::initializeHidlProvider(
+ sp<provider::V2_4::ICameraProvider>& interface,
+ int64_t currentDeviceState) {
+ status_t res = parseProviderName(mProviderName, &mType, &mId);
+ if (res != OK) {
+ ALOGE("%s: Invalid provider name, ignoring", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ ALOGI("Connecting to new camera provider: %s, isRemote? %d",
+ mProviderName.c_str(), interface->isRemote());
+
+ // Determine minor version
+ mMinorVersion = 4;
+ auto cast2_6 = provider::V2_6::ICameraProvider::castFrom(interface);
+ sp<provider::V2_6::ICameraProvider> interface2_6 = nullptr;
+ if (cast2_6.isOk()) {
+ interface2_6 = cast2_6;
+ if (interface2_6 != nullptr) {
+ mMinorVersion = 6;
+ }
+ }
+ // We need to check again since cast2_6.isOk() succeeds even if the provider
+ // version isn't actually 2.6.
+ if (interface2_6 == nullptr){
+ auto cast2_5 =
+ provider::V2_5::ICameraProvider::castFrom(interface);
+ sp<provider::V2_5::ICameraProvider> interface2_5 = nullptr;
+ if (cast2_5.isOk()) {
+ interface2_5 = cast2_5;
+ if (interface != nullptr) {
+ 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)
+ // before setCallback returns
+ hardware::Return<Status> status = interface->setCallback(this);
+ if (!status.isOk()) {
+ ALOGE("%s: Transaction error setting up callbacks with camera provider '%s': %s",
+ __FUNCTION__, mProviderName.c_str(), status.description().c_str());
+ return DEAD_OBJECT;
+ }
+ if (status != Status::OK) {
+ ALOGE("%s: Unable to register callbacks with camera provider '%s'",
+ __FUNCTION__, mProviderName.c_str());
+ return mapToStatusT(status);
+ }
+
+ hardware::Return<bool> linked = interface->linkToDeath(this, /*cookie*/ mId);
+ if (!linked.isOk()) {
+ ALOGE("%s: Transaction error in linking to camera provider '%s' death: %s",
+ __FUNCTION__, mProviderName.c_str(), linked.description().c_str());
+ return DEAD_OBJECT;
+ } else if (!linked) {
+ ALOGW("%s: Unable to link to provider '%s' death notifications",
+ __FUNCTION__, mProviderName.c_str());
+ }
+
+ if (!kEnableLazyHal) {
+ // Save HAL reference indefinitely
+ mSavedInterface = interface;
+ } else {
+ mActiveInterface = interface;
+ }
+
+ ALOGV("%s: Setting device state for %s: 0x%" PRIx64,
+ __FUNCTION__, mProviderName.c_str(), mDeviceState);
+ notifyDeviceStateChange(currentDeviceState);
+
+ res = setUpVendorTags();
+ if (res != OK) {
+ ALOGE("%s: Unable to set up vendor tags from provider '%s'",
+ __FUNCTION__, mProviderName.c_str());
+ return res;
+ }
+
+ // Get initial list of camera devices, if any
+ std::vector<std::string> devices;
+ hardware::Return<void> ret = interface->getCameraIdList([&status, this, &devices](
+ Status idStatus,
+ const hardware::hidl_vec<hardware::hidl_string>& cameraDeviceNames) {
+ status = idStatus;
+ if (status == Status::OK) {
+ for (auto& name : cameraDeviceNames) {
+ uint16_t major, minor;
+ std::string type, id;
+ status_t res = parseDeviceName(name, &major, &minor, &type, &id);
+ if (res != OK) {
+ ALOGE("%s: Error parsing deviceName: %s: %d", __FUNCTION__, name.c_str(), res);
+ status = Status::INTERNAL_ERROR;
+ } else {
+ devices.push_back(name);
+ mProviderPublicCameraIds.push_back(id);
+ }
+ }
+ } });
+ if (!ret.isOk()) {
+ ALOGE("%s: Transaction error in getting camera ID list from provider '%s': %s",
+ __FUNCTION__, mProviderName.c_str(), linked.description().c_str());
+ return DEAD_OBJECT;
+ }
+ if (status != Status::OK) {
+ ALOGE("%s: Unable to query for camera devices from provider '%s'",
+ __FUNCTION__, mProviderName.c_str());
+ return mapToStatusT(status);
+ }
+
+ // Get list of concurrent streaming camera device combinations
+ if (mMinorVersion >= 6) {
+ res = getConcurrentCameraIdsInternalLocked(interface2_6);
+ if (res != OK) {
+ return res;
+ }
+ }
+
+ ret = interface->isSetTorchModeSupported(
+ [this](auto status, bool supported) {
+ if (status == Status::OK) {
+ mSetTorchModeSupported = supported;
+ }
+ });
+ if (!ret.isOk()) {
+ ALOGE("%s: Transaction error checking torch mode support '%s': %s",
+ __FUNCTION__, mProviderName.c_str(), ret.description().c_str());
+ return DEAD_OBJECT;
+ }
+
+ mIsRemote = interface->isRemote();
+
+ sp<StatusListener> listener = mManager->getStatusListener();
+ for (auto& device : devices) {
+ std::string id;
+ status_t res = addDevice(device, common::V1_0::CameraDeviceStatus::PRESENT, &id);
+ if (res != OK) {
+ ALOGE("%s: Unable to enumerate camera device '%s': %s (%d)",
+ __FUNCTION__, device.c_str(), strerror(-res), res);
+ continue;
+ }
+ }
+
+ ALOGI("Camera provider %s ready with %zu camera devices",
+ mProviderName.c_str(), mDevices.size());
+
+ // Process cached status callbacks
+ std::unique_ptr<std::vector<CameraStatusInfoT>> cachedStatus =
+ std::make_unique<std::vector<CameraStatusInfoT>>();
+ {
+ std::lock_guard<std::mutex> lock(mInitLock);
+
+ for (auto& statusInfo : mCachedStatus) {
+ std::string id, physicalId;
+ status_t res = OK;
+ if (statusInfo.isPhysicalCameraStatus) {
+ res = physicalCameraDeviceStatusChangeLocked(&id, &physicalId,
+ statusInfo.cameraId, statusInfo.physicalCameraId,
+ mapToHidlCameraDeviceStatus(statusInfo.status));
+ } else {
+ res = cameraDeviceStatusChangeLocked(&id, statusInfo.cameraId,
+ mapToHidlCameraDeviceStatus(statusInfo.status));
+ }
+ if (res == OK) {
+ cachedStatus->emplace_back(statusInfo.isPhysicalCameraStatus,
+ id.c_str(), physicalId.c_str(), statusInfo.status);
+ }
+ }
+ mCachedStatus.clear();
+
+ mInitialized = true;
+ }
+
+ // The cached status change callbacks cannot be fired directly from this
+ // function, due to same-thread deadlock trying to acquire mInterfaceMutex
+ // twice.
+ if (listener != nullptr) {
+ mInitialStatusCallbackFuture = std::async(std::launch::async,
+ &CameraProviderManager::ProviderInfo::notifyInitialStatusChange, this,
+ listener, std::move(cachedStatus));
+ }
+
+ return OK;
+}
+
+status_t HidlProviderInfo::setUpVendorTags() {
+ if (mVendorTagDescriptor != nullptr)
+ return OK;
+
+ hardware::hidl_vec<VendorTagSection> vts;
+ Status status;
+ hardware::Return<void> ret;
+ const sp<hardware::camera::provider::V2_4::ICameraProvider> interface =
+ startProviderInterface();
+ if (interface == nullptr) {
+ return DEAD_OBJECT;
+ }
+ ret = interface->getVendorTags(
+ [&](auto s, const auto& vendorTagSecs) {
+ status = s;
+ if (s == Status::OK) {
+ vts = vendorTagSecs;
+ }
+ });
+ if (!ret.isOk()) {
+ ALOGE("%s: Transaction error getting vendor tags from provider '%s': %s",
+ __FUNCTION__, mProviderName.c_str(), ret.description().c_str());
+ return DEAD_OBJECT;
+ }
+ if (status != Status::OK) {
+ return mapToStatusT(status);
+ }
+
+ // Read all vendor tag definitions into a descriptor
+ status_t res;
+ if ((res = HidlVendorTagDescriptor::createDescriptorFromHidl(vts, /*out*/mVendorTagDescriptor))
+ != OK) {
+ ALOGE("%s: Could not generate descriptor from vendor tag operations,"
+ "received error %s (%d). Camera clients will not be able to use"
+ "vendor tags", __FUNCTION__, strerror(res), res);
+ return res;
+ }
+
+ return OK;
+}
+
+status_t HidlProviderInfo::notifyDeviceStateChange(int64_t newDeviceState) {
+ mDeviceState = mapToHidlDeviceState(newDeviceState);
+ if (mMinorVersion >= 5) {
+ // Check if the provider is currently active - not going to start it for this notification
+ auto interface = mSavedInterface != nullptr ? mSavedInterface : mActiveInterface.promote();
+ if (interface != nullptr) {
+ // Send current device state
+ auto castResult = provider::V2_5::ICameraProvider::castFrom(interface);
+ if (castResult.isOk()) {
+ sp<provider::V2_5::ICameraProvider> interface_2_5 = castResult;
+ if (interface_2_5 != nullptr) {
+ interface_2_5->notifyDeviceStateChange(mDeviceState);
+ }
+ }
+ }
+ }
+ return OK;
+}
+
+sp<device::V3_2::ICameraDevice>
+HidlProviderInfo::startDeviceInterface(const std::string &name) {
+ Status status;
+ sp<device::V3_2::ICameraDevice> cameraInterface;
+ hardware::Return<void> ret;
+ const sp<provider::V2_4::ICameraProvider> interface = startProviderInterface();
+ if (interface == nullptr) {
+ return nullptr;
+ }
+ ret = interface->getCameraDeviceInterface_V3_x(name, [&status, &cameraInterface](
+ Status s, sp<device::V3_2::ICameraDevice> interface) {
+ status = s;
+ cameraInterface = interface;
+ });
+ if (!ret.isOk()) {
+ ALOGE("%s: Transaction error trying to obtain interface for camera device %s: %s",
+ __FUNCTION__, name.c_str(), ret.description().c_str());
+ return nullptr;
+ }
+ if (status != Status::OK) {
+ ALOGE("%s: Unable to obtain interface for camera device %s: %s", __FUNCTION__,
+ name.c_str(), statusToString(status));
+ return nullptr;
+ }
+ return cameraInterface;
+}
+
+bool HidlProviderInfo::successfullyStartedProviderInterface() {
+ return startProviderInterface() != nullptr;
+}
+
+const sp<provider::V2_4::ICameraProvider>
+HidlProviderInfo::startProviderInterface() {
+ ATRACE_CALL();
+ ALOGV("Request to start camera provider: %s", mProviderName.c_str());
+ if (mSavedInterface != nullptr) {
+ return mSavedInterface;
+ }
+ if (!kEnableLazyHal) {
+ ALOGE("Bad provider state! Should not be here on a non-lazy HAL!");
+ return nullptr;
+ }
+
+ auto interface = mActiveInterface.promote();
+ if (interface == nullptr) {
+ // Try to get service without starting
+ interface = mManager->mHidlServiceProxy->tryGetService(mProviderName);
+ if (interface == nullptr) {
+ ALOGV("Camera provider actually needs restart, calling getService(%s)",
+ mProviderName.c_str());
+ interface = mManager->mHidlServiceProxy->getService(mProviderName);
+
+ // Set all devices as ENUMERATING, provider should update status
+ // to PRESENT after initializing.
+ // This avoids failing getCameraDeviceInterface_V3_x before devices
+ // are ready.
+ for (auto& device : mDevices) {
+ device->mIsDeviceAvailable = false;
+ }
+
+ interface->setCallback(this);
+ hardware::Return<bool>
+ linked = interface->linkToDeath(this, /*cookie*/ mId);
+ if (!linked.isOk()) {
+ ALOGE(
+ "%s: Transaction error in linking to camera provider '%s' death: %s",
+ __FUNCTION__,
+ mProviderName.c_str(),
+ linked.description().c_str());
+ mManager->removeProvider(mProviderName);
+ return nullptr;
+ } else if (!linked) {
+ ALOGW("%s: Unable to link to provider '%s' death notifications",
+ __FUNCTION__, mProviderName.c_str());
+ }
+ // Send current device state
+ if (mMinorVersion >= 5) {
+ auto castResult =
+ provider::V2_5::ICameraProvider::castFrom(interface);
+ if (castResult.isOk()) {
+ sp<provider::V2_5::ICameraProvider> interface_2_5 = castResult;
+ if (interface_2_5 != nullptr) {
+ ALOGV("%s: Initial device state for %s: 0x %" PRIx64,
+ __FUNCTION__, mProviderName.c_str(), mDeviceState);
+ interface_2_5->notifyDeviceStateChange(mDeviceState);
+ }
+ }
+ }
+ }
+ mActiveInterface = interface;
+ } else {
+ ALOGV("Camera provider (%s) already in use. Re-using instance.",
+ mProviderName.c_str());
+ }
+
+ return interface;
+}
+
+hardware::Return<void> HidlProviderInfo::cameraDeviceStatusChange(
+ const hardware::hidl_string& cameraDeviceName,
+ hardware::camera::common::V1_0::CameraDeviceStatus newStatus) {
+ sp<StatusListener> listener;
+ std::string id;
+ std::lock_guard<std::mutex> lock(mInitLock);
+ CameraDeviceStatus internalNewStatus = hidlToInternalCameraDeviceStatus(newStatus);
+ if (!mInitialized) {
+ mCachedStatus.emplace_back(false /*isPhysicalCameraStatus*/,
+ cameraDeviceName.c_str(), std::string().c_str(),
+ internalNewStatus);
+ return hardware::Void();
+ }
+
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+ if (OK != cameraDeviceStatusChangeLocked(&id, cameraDeviceName, newStatus)) {
+ return hardware::Void();
+ }
+ listener = mManager->getStatusListener();
+ }
+
+ // Call without lock held to allow reentrancy into provider manager
+ if (listener != nullptr) {
+ listener->onDeviceStatusChanged(String8(id.c_str()), internalNewStatus);
+ }
+
+ return hardware::Void();
+}
+
+status_t HidlProviderInfo::addDevice(const std::string& name,
+ common::V1_0::CameraDeviceStatus initialStatus, /*out*/ std::string* parsedId) {
+
+ ALOGI("Enumerating new camera device: %s", name.c_str());
+
+ uint16_t major, minor;
+ std::string type, id;
+
+ status_t res = parseDeviceName(name, &major, &minor, &type, &id);
+ if (res != OK) {
+ return res;
+ }
+ if (type != mType) {
+ ALOGE("%s: Device type %s does not match provider type %s", __FUNCTION__,
+ type.c_str(), mType.c_str());
+ return BAD_VALUE;
+ }
+ if (mManager->isValidDeviceLocked(id, major)) {
+ ALOGE("%s: Device %s: ID %s is already in use for device major version %d", __FUNCTION__,
+ name.c_str(), id.c_str(), major);
+ return BAD_VALUE;
+ }
+
+ std::unique_ptr<DeviceInfo> deviceInfo;
+ switch (major) {
+ case 1:
+ ALOGE("%s: Device %s: Unsupported HIDL device HAL major version %d:", __FUNCTION__,
+ name.c_str(), major);
+ return BAD_VALUE;
+ case 3:
+ deviceInfo = initializeDeviceInfo(name, mProviderTagid, id, minor);
+ break;
+ default:
+ ALOGE("%s: Device %s: Unknown HIDL device HAL major version %d:", __FUNCTION__,
+ name.c_str(), major);
+ return BAD_VALUE;
+ }
+ if (deviceInfo == nullptr) return BAD_VALUE;
+ deviceInfo->notifyDeviceStateChange(mDeviceState);
+ deviceInfo->mStatus = hidlToInternalCameraDeviceStatus(initialStatus);
+ bool isAPI1Compatible = deviceInfo->isAPI1Compatible();
+
+ mDevices.push_back(std::move(deviceInfo));
+
+ mUniqueCameraIds.insert(id);
+ if (isAPI1Compatible) {
+ // addDevice can be called more than once for the same camera id if HAL
+ // supports openLegacy.
+ if (std::find(mUniqueAPI1CompatibleCameraIds.begin(), mUniqueAPI1CompatibleCameraIds.end(),
+ id) == mUniqueAPI1CompatibleCameraIds.end()) {
+ mUniqueAPI1CompatibleCameraIds.push_back(id);
+ }
+ }
+
+ if (parsedId != nullptr) {
+ *parsedId = id;
+ }
+ return OK;
+}
+
+status_t HidlProviderInfo::cameraDeviceStatusChangeLocked(
+ std::string* id, const hardware::hidl_string& cameraDeviceName,
+ hardware::camera::common::V1_0::CameraDeviceStatus newStatus) {
+ bool known = false;
+ std::string cameraId;
+ for (auto& deviceInfo : mDevices) {
+ if (deviceInfo->mName == cameraDeviceName) {
+ Mutex::Autolock l(deviceInfo->mDeviceAvailableLock);
+ ALOGI("Camera device %s status is now %s, was %s", cameraDeviceName.c_str(),
+ deviceStatusToString(newStatus),
+ deviceStatusToString(mapToHidlCameraDeviceStatus(deviceInfo->mStatus)));
+ deviceInfo->mStatus = hidlToInternalCameraDeviceStatus(newStatus);
+ // TODO: Handle device removal (NOT_PRESENT)
+ cameraId = deviceInfo->mId;
+ known = true;
+ deviceInfo->mIsDeviceAvailable =
+ (newStatus == hardware::camera::common::V1_0::CameraDeviceStatus::PRESENT);
+ deviceInfo->mDeviceAvailableSignal.signal();
+ break;
+ }
+ }
+ // Previously unseen device; status must not be NOT_PRESENT
+ if (!known) {
+ if (newStatus == hardware::camera::common::V1_0::CameraDeviceStatus::NOT_PRESENT) {
+ ALOGW("Camera provider %s says an unknown camera device %s is not present. Curious.",
+ mProviderName.c_str(), cameraDeviceName.c_str());
+ return BAD_VALUE;
+ }
+ addDevice(cameraDeviceName, newStatus, &cameraId);
+ } else if (newStatus == hardware::camera::common::V1_0::CameraDeviceStatus::NOT_PRESENT) {
+ removeDevice(cameraId);
+ } else if (isExternalLazyHAL()) {
+ // Do not notify CameraService for PRESENT->PRESENT (lazy HAL restart)
+ // because NOT_AVAILABLE is set on CameraService::connect and a PRESENT
+ // notif. would overwrite it
+ return BAD_VALUE;
+ }
+ if (reCacheConcurrentStreamingCameraIdsLocked() != OK) {
+ ALOGE("%s: CameraProvider %s could not re-cache concurrent streaming camera id list ",
+ __FUNCTION__, mProviderName.c_str());
+ }
+ *id = cameraId;
+ return OK;
+}
+
+hardware::Return<void> HidlProviderInfo::physicalCameraDeviceStatusChange(
+ const hardware::hidl_string& cameraDeviceName,
+ const hardware::hidl_string& physicalCameraDeviceName,
+ hardware::camera::common::V1_0::CameraDeviceStatus newStatus) {
+ sp<StatusListener> listener;
+ std::string id;
+ std::string physicalId;
+ std::lock_guard<std::mutex> lock(mInitLock);
+ CameraDeviceStatus newInternalStatus = hidlToInternalCameraDeviceStatus(newStatus);
+ if (!mInitialized) {
+ mCachedStatus.emplace_back(true /*isPhysicalCameraStatus*/, cameraDeviceName,
+ physicalCameraDeviceName, newInternalStatus);
+ return hardware::Void();
+ }
+
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+
+ if (OK != physicalCameraDeviceStatusChangeLocked(&id, &physicalId, cameraDeviceName,
+ physicalCameraDeviceName, newStatus)) {
+ return hardware::Void();
+ }
+
+ listener = mManager->getStatusListener();
+ }
+ // Call without lock held to allow reentrancy into provider manager
+ if (listener != nullptr) {
+ listener->onDeviceStatusChanged(String8(id.c_str()),
+ String8(physicalId.c_str()), newInternalStatus);
+ }
+ return hardware::Void();
+}
+
+status_t HidlProviderInfo::physicalCameraDeviceStatusChangeLocked(
+ std::string* id, std::string* physicalId,
+ const hardware::hidl_string& cameraDeviceName,
+ const hardware::hidl_string& physicalCameraDeviceName,
+ hardware::camera::common::V1_0::CameraDeviceStatus newStatus) {
+ bool known = false;
+ std::string cameraId;
+ for (auto& deviceInfo : mDevices) {
+ if (deviceInfo->mName == cameraDeviceName) {
+ cameraId = deviceInfo->mId;
+ if (!deviceInfo->mIsLogicalCamera) {
+ ALOGE("%s: Invalid combination of camera id %s, physical id %s",
+ __FUNCTION__, cameraId.c_str(), physicalCameraDeviceName.c_str());
+ return BAD_VALUE;
+ }
+ if (std::find(deviceInfo->mPhysicalIds.begin(), deviceInfo->mPhysicalIds.end(),
+ physicalCameraDeviceName) == deviceInfo->mPhysicalIds.end()) {
+ ALOGE("%s: Invalid combination of camera id %s, physical id %s",
+ __FUNCTION__, cameraId.c_str(), physicalCameraDeviceName.c_str());
+ return BAD_VALUE;
+ }
+ ALOGI("Camera device %s physical device %s status is now %s",
+ cameraDeviceName.c_str(), physicalCameraDeviceName.c_str(),
+ deviceStatusToString(newStatus));
+ known = true;
+ break;
+ }
+ }
+ // Previously unseen device; status must not be NOT_PRESENT
+ if (!known) {
+ ALOGW("Camera provider %s says an unknown camera device %s-%s is not present. Curious.",
+ mProviderName.c_str(), cameraDeviceName.c_str(),
+ physicalCameraDeviceName.c_str());
+ return BAD_VALUE;
+ }
+
+ *id = cameraId;
+ *physicalId = physicalCameraDeviceName.c_str();
+ return OK;
+}
+
+hardware::Return<void> HidlProviderInfo::torchModeStatusChange(
+ const hardware::hidl_string& cameraDeviceName,
+ hardware::camera::common::V1_0::TorchModeStatus newStatus) {
+ sp<StatusListener> listener;
+ SystemCameraKind systemCameraKind = SystemCameraKind::PUBLIC;
+ std::string id;
+ bool known = false;
+ {
+ // Hold mLock for accessing mDevices
+ std::lock_guard<std::mutex> lock(mLock);
+ for (auto& deviceInfo : mDevices) {
+ if (deviceInfo->mName == cameraDeviceName) {
+ ALOGI("Camera device %s torch status is now %s", cameraDeviceName.c_str(),
+ torchStatusToString(newStatus));
+ id = deviceInfo->mId;
+ known = true;
+ systemCameraKind = deviceInfo->mSystemCameraKind;
+ if (hardware::camera::common::V1_0::TorchModeStatus::AVAILABLE_ON != newStatus) {
+ mManager->removeRef(CameraProviderManager::DeviceMode::TORCH, id);
+ }
+ break;
+ }
+ }
+ if (!known) {
+ ALOGW("Camera provider %s says an unknown camera %s now has torch status %d. Curious.",
+ mProviderName.c_str(), cameraDeviceName.c_str(), newStatus);
+ return hardware::Void();
+ }
+ // no lock needed since listener is set up only once during
+ // CameraProviderManager initialization and then never changed till it is
+ // destructed.
+ listener = mManager->getStatusListener();
+ }
+ // Call without lock held to allow reentrancy into provider manager
+ // The problem with holding mLock here is that we
+ // might be limiting re-entrancy : CameraService::onTorchStatusChanged calls
+ // back into CameraProviderManager which might try to hold mLock again (eg:
+ // findDeviceInfo, which should be holding mLock while iterating through
+ // each provider's devices).
+ if (listener != nullptr) {
+ listener->onTorchStatusChanged(String8(id.c_str()),
+ hidlToInternalTorchModeStatus(newStatus), systemCameraKind);
+ }
+ return hardware::Void();
+}
+
+void HidlProviderInfo::serviceDied(uint64_t cookie,
+ const wp<hidl::base::V1_0::IBase>& who) {
+ (void) who;
+ ALOGI("Camera provider '%s' has died; removing it", mProviderInstance.c_str());
+ if (cookie != mId) {
+ ALOGW("%s: Unexpected serviceDied cookie %" PRIu64 ", expected %" PRIu32,
+ __FUNCTION__, cookie, mId);
+ }
+ mManager->removeProvider(mProviderInstance);
+}
+
+std::unique_ptr<CameraProviderManager::ProviderInfo::DeviceInfo>
+ HidlProviderInfo::initializeDeviceInfo(
+ const std::string &name, const metadata_vendor_id_t tagId,
+ const std::string &id, uint16_t minorVersion) {
+ Status status;
+
+ auto cameraInterface = startDeviceInterface(name);
+ if (cameraInterface == nullptr) return nullptr;
+
+ common::V1_0::CameraResourceCost resourceCost;
+ cameraInterface->getResourceCost([&status, &resourceCost](
+ Status s, common::V1_0::CameraResourceCost cost) {
+ status = s;
+ resourceCost = cost;
+ });
+ if (status != Status::OK) {
+ ALOGE("%s: Unable to obtain resource costs for camera device %s: %s", __FUNCTION__,
+ name.c_str(), statusToString(status));
+ return nullptr;
+ }
+
+ for (auto& conflictName : resourceCost.conflictingDevices) {
+ uint16_t major, minor;
+ std::string type, id;
+ status_t res = parseDeviceName(conflictName, &major, &minor, &type, &id);
+ if (res != OK) {
+ ALOGE("%s: Failed to parse conflicting device %s", __FUNCTION__, conflictName.c_str());
+ return nullptr;
+ }
+ conflictName = id;
+ }
+
+ return std::unique_ptr<DeviceInfo3>(
+ new HidlDeviceInfo3(name, tagId, id, minorVersion, hidlToInternalResourceCost(resourceCost),
+ this, mProviderPublicCameraIds, cameraInterface));
+}
+
+status_t HidlProviderInfo::reCacheConcurrentStreamingCameraIdsLocked() {
+ if (mMinorVersion < 6) {
+ // Unsupported operation, nothing to do here
+ return OK;
+ }
+ // Check if the provider is currently active - not going to start it up for this notification
+ auto interface = mSavedInterface != nullptr ? mSavedInterface : mActiveInterface.promote();
+ if (interface == nullptr) {
+ ALOGE("%s: camera provider interface for %s is not valid", __FUNCTION__,
+ mProviderName.c_str());
+ return INVALID_OPERATION;
+ }
+ auto castResult = provider::V2_6::ICameraProvider::castFrom(interface);
+
+ if (castResult.isOk()) {
+ sp<provider::V2_6::ICameraProvider> interface2_6 = castResult;
+ if (interface2_6 != nullptr) {
+ return getConcurrentCameraIdsInternalLocked(interface2_6);
+ } else {
+ // This should not happen since mMinorVersion >= 6
+ ALOGE("%s: mMinorVersion was >= 6, but interface2_6 was nullptr", __FUNCTION__);
+ return UNKNOWN_ERROR;
+ }
+ }
+ return OK;
+}
+
+status_t HidlProviderInfo::getConcurrentCameraIdsInternalLocked(
+ sp<provider::V2_6::ICameraProvider> &interface2_6) {
+ if (interface2_6 == nullptr) {
+ ALOGE("%s: null interface provided", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ Status status = Status::OK;
+ hardware::Return<void> ret =
+ interface2_6->getConcurrentStreamingCameraIds([&status, this](
+ Status concurrentIdStatus, // TODO: Move all instances of hidl_string to 'using'
+ const hardware::hidl_vec<hardware::hidl_vec<hardware::hidl_string>>&
+ cameraDeviceIdCombinations) {
+ status = concurrentIdStatus;
+ if (status == Status::OK) {
+ mConcurrentCameraIdCombinations.clear();
+ for (auto& combination : cameraDeviceIdCombinations) {
+ std::unordered_set<std::string> deviceIds;
+ for (auto &cameraDeviceId : combination) {
+ deviceIds.insert(cameraDeviceId.c_str());
+ }
+ mConcurrentCameraIdCombinations.push_back(std::move(deviceIds));
+ }
+ } });
+ if (!ret.isOk()) {
+ ALOGE("%s: Transaction error in getting concurrent camera ID list from provider '%s'",
+ __FUNCTION__, mProviderName.c_str());
+ return DEAD_OBJECT;
+ }
+ if (status != Status::OK) {
+ ALOGE("%s: Unable to query for camera devices from provider '%s'",
+ __FUNCTION__, mProviderName.c_str());
+ return mapToStatusT(status);
+ }
+ return OK;
+}
+
+HidlProviderInfo::HidlDeviceInfo3::HidlDeviceInfo3(
+ const std::string& name,
+ const metadata_vendor_id_t tagId,
+ const std::string &id, uint16_t minorVersion,
+ const CameraResourceCost& resourceCost,
+ sp<CameraProviderManager::ProviderInfo> parentProvider,
+ const std::vector<std::string>& publicCameraIds,
+ sp<hardware::camera::device::V3_2::ICameraDevice> interface) :
+ DeviceInfo3(name, tagId, id, minorVersion, resourceCost, parentProvider, publicCameraIds) {
+
+ // Get camera characteristics and initialize flash unit availability
+ Status status;
+ hardware::Return<void> ret;
+ ret = interface->getCameraCharacteristics([&status, this](Status s,
+ device::V3_2::CameraMetadata metadata) {
+ status = s;
+ if (s == Status::OK) {
+ camera_metadata_t *buffer =
+ reinterpret_cast<camera_metadata_t*>(metadata.data());
+ size_t expectedSize = metadata.size();
+ int res = validate_camera_metadata_structure(buffer, &expectedSize);
+ if (res == OK || res == CAMERA_METADATA_VALIDATION_SHIFTED) {
+ set_camera_metadata_vendor_id(buffer, mProviderTagid);
+ mCameraCharacteristics = buffer;
+ } else {
+ ALOGE("%s: Malformed camera metadata received from HAL", __FUNCTION__);
+ status = Status::INTERNAL_ERROR;
+ }
+ }
+ });
+ if (!ret.isOk()) {
+ ALOGE("%s: Transaction error getting camera characteristics for device %s"
+ " to check for a flash unit: %s", __FUNCTION__, id.c_str(),
+ ret.description().c_str());
+ return;
+ }
+ if (status != Status::OK) {
+ ALOGE("%s: Unable to get camera characteristics for device %s: %s (%d)",
+ __FUNCTION__, id.c_str(), statusToString(status), status);
+ return;
+ }
+
+ if (mCameraCharacteristics.exists(ANDROID_INFO_DEVICE_STATE_ORIENTATIONS)) {
+ const auto &stateMap = mCameraCharacteristics.find(ANDROID_INFO_DEVICE_STATE_ORIENTATIONS);
+ if ((stateMap.count > 0) && ((stateMap.count % 2) == 0)) {
+ for (size_t i = 0; i < stateMap.count; i += 2) {
+ mDeviceStateOrientationMap.emplace(stateMap.data.i64[i], stateMap.data.i64[i+1]);
+ }
+ } else {
+ ALOGW("%s: Invalid ANDROID_INFO_DEVICE_STATE_ORIENTATIONS map size: %zu", __FUNCTION__,
+ stateMap.count);
+ }
+ }
+
+ mSystemCameraKind = getSystemCameraKind();
+
+ status_t res = fixupMonochromeTags();
+ if (OK != res) {
+ ALOGE("%s: Unable to fix up monochrome tags based for older HAL version: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return;
+ }
+ auto stat = addDynamicDepthTags();
+ if (OK != stat) {
+ ALOGE("%s: Failed appending dynamic depth tags: %s (%d)", __FUNCTION__, strerror(-stat),
+ stat);
+ }
+ res = deriveHeicTags();
+ if (OK != res) {
+ ALOGE("%s: Unable to derive HEIC tags based on camera and media capabilities: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ }
+
+ if (SessionConfigurationUtils::isUltraHighResolutionSensor(mCameraCharacteristics)) {
+ status_t status = addDynamicDepthTags(/*maxResolution*/true);
+ if (OK != status) {
+ ALOGE("%s: Failed appending dynamic depth tags for maximum resolution mode: %s (%d)",
+ __FUNCTION__, strerror(-status), status);
+ }
+
+ status = deriveHeicTags(/*maxResolution*/true);
+ if (OK != status) {
+ ALOGE("%s: Unable to derive HEIC tags based on camera and media capabilities for"
+ "maximum resolution mode: %s (%d)", __FUNCTION__, strerror(-status), status);
+ }
+ }
+
+ res = addRotateCropTags();
+ if (OK != res) {
+ ALOGE("%s: Unable to add default SCALER_ROTATE_AND_CROP tags: %s (%d)", __FUNCTION__,
+ strerror(-res), res);
+ }
+ res = addPreCorrectionActiveArraySize();
+ if (OK != res) {
+ ALOGE("%s: Unable to add PRE_CORRECTION_ACTIVE_ARRAY_SIZE: %s (%d)", __FUNCTION__,
+ strerror(-res), res);
+ }
+ res = camera3::ZoomRatioMapper::overrideZoomRatioTags(
+ &mCameraCharacteristics, &mSupportNativeZoomRatio);
+ if (OK != res) {
+ ALOGE("%s: Unable to override zoomRatio related tags: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ }
+
+ camera_metadata_entry flashAvailable =
+ mCameraCharacteristics.find(ANDROID_FLASH_INFO_AVAILABLE);
+ if (flashAvailable.count == 1 &&
+ flashAvailable.data.u8[0] == ANDROID_FLASH_INFO_AVAILABLE_TRUE) {
+ mHasFlashUnit = true;
+ } else {
+ mHasFlashUnit = false;
+ }
+
+ camera_metadata_entry entry =
+ mCameraCharacteristics.find(ANDROID_FLASH_INFO_STRENGTH_DEFAULT_LEVEL);
+ if (entry.count == 1) {
+ mTorchDefaultStrengthLevel = entry.data.i32[0];
+ } else {
+ mTorchDefaultStrengthLevel = 0;
+ }
+ entry = mCameraCharacteristics.find(ANDROID_FLASH_INFO_STRENGTH_MAXIMUM_LEVEL);
+ if (entry.count == 1) {
+ mTorchMaximumStrengthLevel = entry.data.i32[0];
+ } else {
+ mTorchMaximumStrengthLevel = 0;
+ }
+
+ mTorchStrengthLevel = 0;
+
+ queryPhysicalCameraIds();
+
+ // Get physical camera characteristics if applicable
+ auto castResult = device::V3_5::ICameraDevice::castFrom(interface);
+ if (!castResult.isOk()) {
+ ALOGV("%s: Unable to convert ICameraDevice instance to version 3.5", __FUNCTION__);
+ return;
+ }
+ sp<device::V3_5::ICameraDevice> interface_3_5 = castResult;
+ if (interface_3_5 == nullptr) {
+ ALOGE("%s: Converted ICameraDevice instance to nullptr", __FUNCTION__);
+ return;
+ }
+
+ if (mIsLogicalCamera) {
+ for (auto& id : mPhysicalIds) {
+ if (std::find(mPublicCameraIds.begin(), mPublicCameraIds.end(), id) !=
+ mPublicCameraIds.end()) {
+ continue;
+ }
+
+ hardware::hidl_string hidlId(id);
+ ret = interface_3_5->getPhysicalCameraCharacteristics(hidlId,
+ [&status, &id, this](Status s, device::V3_2::CameraMetadata metadata) {
+ status = s;
+ if (s == Status::OK) {
+ camera_metadata_t *buffer =
+ reinterpret_cast<camera_metadata_t*>(metadata.data());
+ size_t expectedSize = metadata.size();
+ int res = validate_camera_metadata_structure(buffer, &expectedSize);
+ if (res == OK || res == CAMERA_METADATA_VALIDATION_SHIFTED) {
+ set_camera_metadata_vendor_id(buffer, mProviderTagid);
+ mPhysicalCameraCharacteristics[id] = buffer;
+ } else {
+ ALOGE("%s: Malformed camera metadata received from HAL", __FUNCTION__);
+ status = Status::INTERNAL_ERROR;
+ }
+ }
+ });
+
+ if (!ret.isOk()) {
+ ALOGE("%s: Transaction error getting physical camera %s characteristics for %s: %s",
+ __FUNCTION__, id.c_str(), id.c_str(), ret.description().c_str());
+ return;
+ }
+ if (status != Status::OK) {
+ ALOGE("%s: Unable to get physical camera %s characteristics for device %s: %s (%d)",
+ __FUNCTION__, id.c_str(), mId.c_str(),
+ statusToString(status), status);
+ return;
+ }
+
+ res = camera3::ZoomRatioMapper::overrideZoomRatioTags(
+ &mPhysicalCameraCharacteristics[id], &mSupportNativeZoomRatio);
+ if (OK != res) {
+ ALOGE("%s: Unable to override zoomRatio related tags: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ }
+ }
+ }
+
+ if (!kEnableLazyHal) {
+ // Save HAL reference indefinitely
+ mSavedInterface = interface;
+ }
+
+
+}
+
+status_t HidlProviderInfo::HidlDeviceInfo3::setTorchMode(bool enabled) {
+ using hardware::camera::common::V1_0::TorchMode;
+ const sp<hardware::camera::device::V3_2::ICameraDevice> interface = startDeviceInterface();
+ Status s = interface->setTorchMode(enabled ? TorchMode::ON : TorchMode::OFF);
+ return mapToStatusT(s);
+}
+
+status_t HidlProviderInfo::HidlDeviceInfo3::turnOnTorchWithStrengthLevel(
+ int32_t torchStrength) {
+ const sp<hardware::camera::device::V3_2::ICameraDevice> interface = startDeviceInterface();
+ if (interface == nullptr) {
+ return DEAD_OBJECT;
+ }
+ sp<hardware::camera::device::V3_8::ICameraDevice> interface_3_8 = nullptr;
+ auto castResult_3_8 = device::V3_8::ICameraDevice::castFrom(interface);
+ if (castResult_3_8.isOk()) {
+ interface_3_8 = castResult_3_8;
+ }
+
+ if (interface_3_8 == nullptr) {
+ return INVALID_OPERATION;
+ }
+
+ Status s = interface_3_8->turnOnTorchWithStrengthLevel(torchStrength);
+ if (s == Status::OK) {
+ mTorchStrengthLevel = torchStrength;
+ }
+ return mapToStatusT(s);
+}
+
+status_t HidlProviderInfo::HidlDeviceInfo3::getTorchStrengthLevel(int32_t *torchStrength) {
+ if (torchStrength == nullptr) {
+ return BAD_VALUE;
+ }
+ const sp<hardware::camera::device::V3_2::ICameraDevice> interface = startDeviceInterface();
+ if (interface == nullptr) {
+ return DEAD_OBJECT;
+ }
+ auto castResult_3_8 = device::V3_8::ICameraDevice::castFrom(interface);
+ sp<hardware::camera::device::V3_8::ICameraDevice> interface_3_8 = nullptr;
+ if (castResult_3_8.isOk()) {
+ interface_3_8 = castResult_3_8;
+ }
+
+ if (interface_3_8 == nullptr) {
+ return INVALID_OPERATION;
+ }
+
+ Status callStatus;
+ status_t res;
+ hardware::Return<void> ret = interface_3_8->getTorchStrengthLevel([&callStatus, &torchStrength]
+ (Status status, const int32_t& torchStrengthLevel) {
+ callStatus = status;
+ if (status == Status::OK) {
+ *torchStrength = torchStrengthLevel;
+ } });
+
+ 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: Get torch strength level failed: %d", __FUNCTION__, callStatus);
+ res = UNKNOWN_ERROR;
+ }
+ } else {
+ ALOGE("%s: Unexpected binder error: %s", __FUNCTION__, ret.description().c_str());
+ res = UNKNOWN_ERROR;
+ }
+
+ return res;
+}
+
+sp<hardware::camera::device::V3_2::ICameraDevice>
+HidlProviderInfo::HidlDeviceInfo3::startDeviceInterface() {
+ Mutex::Autolock l(mDeviceAvailableLock);
+ sp<hardware::camera::device::V3_2::ICameraDevice> device;
+ ATRACE_CALL();
+ if (mSavedInterface == nullptr) {
+ sp<HidlProviderInfo> parentProvider =
+ static_cast<HidlProviderInfo *>(mParentProvider.promote().get());
+ if (parentProvider != nullptr) {
+ // Wait for lazy HALs to confirm device availability
+ if (parentProvider->isExternalLazyHAL() && !mIsDeviceAvailable) {
+ ALOGV("%s: Wait for external device to become available %s",
+ __FUNCTION__,
+ mId.c_str());
+
+ auto res = mDeviceAvailableSignal.waitRelative(mDeviceAvailableLock,
+ kDeviceAvailableTimeout);
+ if (res != OK) {
+ ALOGE("%s: Failed waiting for device to become available",
+ __FUNCTION__);
+ return nullptr;
+ }
+ }
+
+ device = parentProvider->startDeviceInterface(mName);
+ }
+ } else {
+ device = (hardware::camera::device::V3_2::ICameraDevice *) mSavedInterface.get();
+ }
+ return device;
+}
+
+status_t HidlProviderInfo::HidlDeviceInfo3::dumpState(int fd) {
+ native_handle_t* handle = native_handle_create(1,0);
+ handle->data[0] = fd;
+ const sp<hardware::camera::device::V3_2::ICameraDevice> interface =
+ startDeviceInterface();
+ if (interface == nullptr) {
+ return DEAD_OBJECT;
+ }
+ auto ret = interface->dumpState(handle);
+ native_handle_delete(handle);
+ if (!ret.isOk()) {
+ return INVALID_OPERATION;
+ }
+ return OK;
+}
+
+status_t HidlProviderInfo::HidlDeviceInfo3::isSessionConfigurationSupported(
+ const SessionConfiguration &configuration, bool overrideForPerfClass, bool *status) {
+
+ hardware::camera::device::V3_8::StreamConfiguration streamConfiguration;
+ bool earlyExit = false;
+ camera3::metadataGetter getMetadata = [this](const String8 &id, bool /*overrideForPerfClass*/) {
+ CameraMetadata physicalChars;
+ getPhysicalCameraCharacteristics(id.c_str(), &physicalChars);
+ return physicalChars;
+ };
+ auto bRes = SessionConfigurationUtils::convertToHALStreamCombination(configuration,
+ String8(mId.c_str()), mCameraCharacteristics, getMetadata, mPhysicalIds,
+ streamConfiguration, overrideForPerfClass, &earlyExit);
+
+ if (!bRes.isOk()) {
+ return UNKNOWN_ERROR;
+ }
+
+ if (earlyExit) {
+ *status = false;
+ return OK;
+ }
+
+ const sp<hardware::camera::device::V3_2::ICameraDevice> interface =
+ startDeviceInterface();
+
+ if (interface == nullptr) {
+ return DEAD_OBJECT;
+ }
+
+ 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;
+ auto castResult_3_8 = device::V3_8::ICameraDevice::castFrom(interface);
+ sp<hardware::camera::device::V3_8::ICameraDevice> interface_3_8 = castResult_3_8;
+
+ status_t res;
+ Status callStatus;
+ ::android::hardware::Return<void> ret;
+ auto halCb =
+ [&callStatus, &status] (Status s, bool combStatus) {
+ callStatus = s;
+ *status = combStatus;
+ };
+ if (interface_3_8 != nullptr) {
+ ret = interface_3_8->isStreamCombinationSupported_3_8(streamConfiguration, halCb);
+ } else if (interface_3_7 != nullptr) {
+ hardware::camera::device::V3_7::StreamConfiguration configuration_3_7;
+ bool success = SessionConfigurationUtils::convertHALStreamCombinationFromV38ToV37(
+ configuration_3_7, streamConfiguration);
+ if (!success) {
+ *status = false;
+ return OK;
+ }
+ ret = interface_3_7->isStreamCombinationSupported_3_7(configuration_3_7, halCb);
+ } else if (interface_3_5 != nullptr) {
+ hardware::camera::device::V3_7::StreamConfiguration configuration_3_7;
+ bool success = SessionConfigurationUtils::convertHALStreamCombinationFromV38ToV37(
+ configuration_3_7, streamConfiguration);
+ if (!success) {
+ *status = false;
+ return OK;
+ }
+ hardware::camera::device::V3_4::StreamConfiguration configuration_3_4;
+ success = SessionConfigurationUtils::convertHALStreamCombinationFromV37ToV34(
+ configuration_3_4, configuration_3_7);
+ if (!success) {
+ *status = false;
+ return OK;
+ }
+ ret = interface_3_5->isStreamCombinationSupported(configuration_3_4, halCb);
+ } else {
+ return INVALID_OPERATION;
+ }
+ 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;
+}
+
+status_t HidlProviderInfo::convertToHALStreamCombinationAndCameraIdsLocked(
+ const std::vector<CameraIdAndSessionConfiguration> &cameraIdsAndSessionConfigs,
+ const std::set<std::string>& perfClassPrimaryCameraIds,
+ int targetSdkVersion,
+ hardware::hidl_vec<CameraIdAndStreamCombination> *halCameraIdsAndStreamCombinations,
+ bool *earlyExit) {
+ binder::Status bStatus = binder::Status::ok();
+ std::vector<CameraIdAndStreamCombination> halCameraIdsAndStreamsV;
+ bool shouldExit = false;
+ status_t res = OK;
+ for (auto &cameraIdAndSessionConfig : cameraIdsAndSessionConfigs) {
+ const std::string& cameraId = cameraIdAndSessionConfig.mCameraId;
+ hardware::camera::device::V3_8::StreamConfiguration streamConfiguration;
+ CameraMetadata deviceInfo;
+ bool overrideForPerfClass =
+ SessionConfigurationUtils::targetPerfClassPrimaryCamera(
+ perfClassPrimaryCameraIds, cameraId, targetSdkVersion);
+ res = mManager->getCameraCharacteristicsLocked(cameraId, overrideForPerfClass, &deviceInfo);
+ if (res != OK) {
+ return res;
+ }
+ camera3::metadataGetter getMetadata =
+ [this](const String8 &id, bool overrideForPerfClass) {
+ CameraMetadata physicalDeviceInfo;
+ mManager->getCameraCharacteristicsLocked(id.string(), overrideForPerfClass,
+ &physicalDeviceInfo);
+ return physicalDeviceInfo;
+ };
+ std::vector<std::string> physicalCameraIds;
+ mManager->isLogicalCameraLocked(cameraId, &physicalCameraIds);
+ bStatus =
+ SessionConfigurationUtils::convertToHALStreamCombination(
+ cameraIdAndSessionConfig.mSessionConfiguration,
+ String8(cameraId.c_str()), deviceInfo, getMetadata,
+ physicalCameraIds, streamConfiguration,
+ overrideForPerfClass, &shouldExit);
+ if (!bStatus.isOk()) {
+ ALOGE("%s: convertToHALStreamCombination failed", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ if (shouldExit) {
+ *earlyExit = true;
+ return OK;
+ }
+ CameraIdAndStreamCombination halCameraIdAndStream;
+ halCameraIdAndStream.cameraId = cameraId;
+ SessionConfigurationUtils::convertHALStreamCombinationFromV38ToV37(
+ halCameraIdAndStream.streamConfiguration, streamConfiguration);
+ halCameraIdsAndStreamsV.push_back(halCameraIdAndStream);
+ }
+ *halCameraIdsAndStreamCombinations = halCameraIdsAndStreamsV;
+ return OK;
+}
+
+status_t HidlProviderInfo::isConcurrentSessionConfigurationSupported(
+ const std::vector<CameraIdAndSessionConfiguration> &cameraIdsAndSessionConfigs,
+ const std::set<std::string>& perfClassPrimaryCameraIds,
+ int targetSdkVersion, bool *isSupported) {
+
+ hardware::hidl_vec<CameraIdAndStreamCombination> halCameraIdsAndStreamCombinations;
+ bool knowUnsupported = false;
+ status_t res = convertToHALStreamCombinationAndCameraIdsLocked(
+ cameraIdsAndSessionConfigs, perfClassPrimaryCameraIds,
+ targetSdkVersion, &halCameraIdsAndStreamCombinations, &knowUnsupported);
+ if (res != OK) {
+ ALOGE("%s unable to convert session configurations provided to HAL stream"
+ "combinations", __FUNCTION__);
+ return res;
+ }
+ if (knowUnsupported) {
+ // We got to know the streams aren't valid before doing the HAL
+ // call itself.
+ *isSupported = false;
+ return OK;
+ }
+
+ if (mMinorVersion >= 6) {
+ // Check if the provider is currently active - not going to start it for this notification
+ auto interface = mSavedInterface != nullptr ? mSavedInterface : mActiveInterface.promote();
+ if (interface == nullptr) {
+ // TODO: This might be some other problem
+ return INVALID_OPERATION;
+ }
+ 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; };
+
+ ::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++) {
+ using namespace camera3;
+ 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
+ return INVALID_OPERATION;
+}
+
+status_t HidlVendorTagDescriptor::createDescriptorFromHidl(
+ const hardware::hidl_vec<common::V1_0::VendorTagSection>& vts,
+ sp<VendorTagDescriptor>& descriptor) {
+
+ int tagCount = 0;
+
+ for (size_t s = 0; s < vts.size(); s++) {
+ tagCount += vts[s].tags.size();
+ }
+
+ if (tagCount < 0 || tagCount > INT32_MAX) {
+ ALOGE("%s: tag count %d from vendor tag sections is invalid.", __FUNCTION__, tagCount);
+ return BAD_VALUE;
+ }
+
+ Vector<uint32_t> tagArray;
+ LOG_ALWAYS_FATAL_IF(tagArray.resize(tagCount) != tagCount,
+ "%s: too many (%u) vendor tags defined.", __FUNCTION__, tagCount);
+
+
+ sp<HidlVendorTagDescriptor> desc = new HidlVendorTagDescriptor();
+ desc->mTagCount = tagCount;
+
+ SortedVector<String8> sections;
+ KeyedVector<uint32_t, String8> tagToSectionMap;
+
+ int idx = 0;
+ for (size_t s = 0; s < vts.size(); s++) {
+ const common::V1_0::VendorTagSection& section = vts[s];
+ const char *sectionName = section.sectionName.c_str();
+ if (sectionName == NULL) {
+ ALOGE("%s: no section name defined for vendor tag section %zu.", __FUNCTION__, s);
+ return BAD_VALUE;
+ }
+ String8 sectionString(sectionName);
+ sections.add(sectionString);
+
+ for (size_t j = 0; j < section.tags.size(); j++) {
+ uint32_t tag = section.tags[j].tagId;
+ if (tag < CAMERA_METADATA_VENDOR_TAG_BOUNDARY) {
+ ALOGE("%s: vendor tag %d not in vendor tag section.", __FUNCTION__, tag);
+ return BAD_VALUE;
+ }
+
+ tagArray.editItemAt(idx++) = section.tags[j].tagId;
+
+ const char *tagName = section.tags[j].tagName.c_str();
+ if (tagName == NULL) {
+ ALOGE("%s: no tag name defined for vendor tag %d.", __FUNCTION__, tag);
+ return BAD_VALUE;
+ }
+ desc->mTagToNameMap.add(tag, String8(tagName));
+ tagToSectionMap.add(tag, sectionString);
+
+ int tagType = (int) section.tags[j].tagType;
+ if (tagType < 0 || tagType >= NUM_TYPES) {
+ ALOGE("%s: tag type %d from vendor ops does not exist.", __FUNCTION__, tagType);
+ return BAD_VALUE;
+ }
+ desc->mTagToTypeMap.add(tag, tagType);
+ }
+ }
+
+ desc->mSections = sections;
+
+ for (size_t i = 0; i < tagArray.size(); ++i) {
+ uint32_t tag = tagArray[i];
+ String8 sectionString = tagToSectionMap.valueFor(tag);
+
+ // Set up tag to section index map
+ ssize_t index = sections.indexOf(sectionString);
+ LOG_ALWAYS_FATAL_IF(index < 0, "index %zd must be non-negative", index);
+ desc->mTagToSectionMap.add(tag, static_cast<uint32_t>(index));
+
+ // Set up reverse mapping
+ ssize_t reverseIndex = -1;
+ if ((reverseIndex = desc->mReverseMapping.indexOfKey(sectionString)) < 0) {
+ KeyedVector<String8, uint32_t>* nameMapper = new KeyedVector<String8, uint32_t>();
+ reverseIndex = desc->mReverseMapping.add(sectionString, nameMapper);
+ }
+ desc->mReverseMapping[reverseIndex]->add(desc->mTagToNameMap.valueFor(tag), tag);
+ }
+
+ descriptor = std::move(desc);
+ return OK;
+}
+
+} //namespace android
diff --git a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.h b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.h
new file mode 100644
index 0000000..0ba2aff
--- /dev/null
+++ b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.h
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2022 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_SERVERS_CAMERA_CAMERAPROVIDER_HIDLPROVIDERINFOH
+#define ANDROID_SERVERS_CAMERA_CAMERAPROVIDER_HIDLPROVIDERINFOH
+
+#include "common/CameraProviderManager.h"
+
+namespace android {
+
+/**
+ * The vendor tag descriptor class that takes HIDL vendor tag information as
+ * input. Not part of VendorTagDescriptor class because that class is used
+ * in AIDL generated sources which don't have access to HIDL headers.
+ */
+class HidlVendorTagDescriptor : public VendorTagDescriptor {
+public:
+ /**
+ * Create a VendorTagDescriptor object from the HIDL VendorTagSection
+ * vector.
+ *
+ * Returns OK on success, or a negative error code.
+ */
+ static status_t createDescriptorFromHidl(
+ const hardware::hidl_vec<hardware::camera::common::V1_0::VendorTagSection>& vts,
+ /*out*/
+ sp<VendorTagDescriptor>& descriptor);
+};
+
+struct HidlProviderInfo : public CameraProviderManager::ProviderInfo,
+ virtual public hardware::camera::provider::V2_6::ICameraProviderCallback,
+ virtual public hardware::hidl_death_recipient {
+ // Current overall Android device physical status
+ hardware::hidl_bitfield<hardware::camera::provider::V2_5::DeviceState> mDeviceState;
+
+ // This pointer is used to keep a reference to the ICameraProvider that was last accessed.
+ wp<hardware::camera::provider::V2_4::ICameraProvider> mActiveInterface;
+
+ sp<hardware::camera::provider::V2_4::ICameraProvider> mSavedInterface;
+ HidlProviderInfo(
+ const std::string &providerName,
+ const std::string &providerInstance,
+ CameraProviderManager *manager) :
+ CameraProviderManager::ProviderInfo(providerName, providerInstance, manager) {}
+
+ virtual ~HidlProviderInfo() {}
+
+ static status_t mapToStatusT(const hardware::camera::common::V1_0::Status &status);
+
+ status_t initializeHidlProvider(
+ sp<hardware::camera::provider::V2_4::ICameraProvider>& interface,
+ int64_t currentDeviceState);
+
+ IPCTransport getIPCTransport() override {return IPCTransport::HIDL;}
+
+ const sp<hardware::camera::provider::V2_4::ICameraProvider> startProviderInterface();
+
+ virtual bool successfullyStartedProviderInterface() override;
+
+ virtual status_t setUpVendorTags() override;
+ virtual status_t notifyDeviceStateChange(int64_t) override;
+
+ /**
+ * Query the camera provider for concurrent stream configuration support
+ */
+ virtual status_t isConcurrentSessionConfigurationSupported(
+ const std::vector<CameraIdAndSessionConfiguration> &cameraIdsAndSessionConfigs,
+ const std::set<std::string>& perfClassPrimaryCameraIds,
+ int targetSdkVersion, bool *isSupported) override;
+
+ // Helper for initializeDeviceInfo to use the right CameraProvider get method.
+ sp<hardware::camera::device::V3_2::ICameraDevice>
+ startDeviceInterface(const std::string &deviceName);
+
+ // ICameraProviderCallbacks interface - these lock the parent mInterfaceMutex
+ hardware::Return<void> cameraDeviceStatusChange(
+ const hardware::hidl_string& ,
+ hardware::camera::common::V1_0::CameraDeviceStatus ) override;
+ hardware::Return<void> torchModeStatusChange(
+ const hardware::hidl_string& ,
+ hardware::camera::common::V1_0::TorchModeStatus ) override;
+ hardware::Return<void> physicalCameraDeviceStatusChange(
+ const hardware::hidl_string& ,
+ const hardware::hidl_string& ,
+ hardware::camera::common::V1_0::CameraDeviceStatus ) override;
+
+ // hidl_death_recipient interface - this locks the parent mInterfaceMutex
+ virtual void serviceDied(uint64_t , const wp<hidl::base::V1_0::IBase>& ) override;
+
+ struct HidlDeviceInfo3 : public CameraProviderManager::ProviderInfo::DeviceInfo3 {
+
+ const hardware::hidl_version mVersion = hardware::hidl_version{3, 2};
+ sp<IBase> mSavedInterface = nullptr;
+
+ HidlDeviceInfo3(const std::string& , const metadata_vendor_id_t ,
+ const std::string &, uint16_t ,
+ const CameraResourceCost& ,
+ sp<ProviderInfo> ,
+ const std::vector<std::string>& ,
+ sp<hardware::camera::device::V3_2::ICameraDevice>);
+
+ ~HidlDeviceInfo3() {}
+
+ virtual status_t setTorchMode(bool enabled) override;
+ virtual status_t turnOnTorchWithStrengthLevel(int32_t torchStrength) override;
+ virtual status_t getTorchStrengthLevel(int32_t *torchStrength) override;
+
+ virtual status_t dumpState(int fd) override;
+
+ virtual status_t isSessionConfigurationSupported(
+ const SessionConfiguration &/*configuration*/,
+ bool overrideForPerfClass,
+ bool *status/*status*/);
+ sp<hardware::camera::device::V3_2::ICameraDevice> startDeviceInterface();
+ };
+
+ private:
+
+ status_t cameraDeviceStatusChangeLocked(
+ std::string* , const hardware::hidl_string& ,
+ hardware::camera::common::V1_0::CameraDeviceStatus );
+
+ status_t physicalCameraDeviceStatusChangeLocked(
+ std::string* , std::string* ,
+ const hardware::hidl_string& ,
+ const hardware::hidl_string& ,
+ hardware::camera::common::V1_0::CameraDeviceStatus );
+
+ status_t addDevice(const std::string& ,
+ hardware::camera::common::V1_0::CameraDeviceStatus ,
+ /*out*/ std::string *);
+
+ std::unique_ptr<DeviceInfo> initializeDeviceInfo(const std::string &,
+ const metadata_vendor_id_t , const std::string &,
+ uint16_t );
+ status_t reCacheConcurrentStreamingCameraIdsLocked();
+
+ //Expects to have mLock locked
+ status_t getConcurrentCameraIdsInternalLocked(
+ sp<hardware::camera::provider::V2_6::ICameraProvider> &);
+
+ //expects to have mManager->mInterfaceMutex locked
+ status_t convertToHALStreamCombinationAndCameraIdsLocked(
+ const std::vector<hardware::camera2::utils::CameraIdAndSessionConfiguration>&
+ cameraIdsAndSessionConfigs,
+ const std::set<std::string>& perfClassPrimaryCameraIds,
+ int targetSdkVersion,
+ hardware::hidl_vec<hardware::camera::provider::V2_7::CameraIdAndStreamCombination>*
+ halCameraIdsAndStreamCombinations,
+ bool *earlyExit);
+}; // HidlProviderInfo
+
+} // namespace android
+#endif
diff --git a/services/camera/libcameraservice/device3/BufferUtils.cpp b/services/camera/libcameraservice/device3/BufferUtils.cpp
index f3adf20..c0d47d5 100644
--- a/services/camera/libcameraservice/device3/BufferUtils.cpp
+++ b/services/camera/libcameraservice/device3/BufferUtils.cpp
@@ -28,16 +28,6 @@
namespace android {
namespace camera3 {
-camera_buffer_status_t mapHidlBufferStatus(hardware::camera::device::V3_2::BufferStatus status) {
- using hardware::camera::device::V3_2::BufferStatus;
-
- switch (status) {
- case BufferStatus::OK: return CAMERA_BUFFER_STATUS_OK;
- case BufferStatus::ERROR: return CAMERA_BUFFER_STATUS_ERROR;
- }
- return CAMERA_BUFFER_STATUS_ERROR;
-}
-
void BufferRecords::takeInflightBufferMap(BufferRecords& other) {
std::lock_guard<std::mutex> oLock(other.mInflightLock);
std::lock_guard<std::mutex> lock(mInflightLock);
diff --git a/services/camera/libcameraservice/device3/BufferUtils.h b/services/camera/libcameraservice/device3/BufferUtils.h
index 03112ec..96fc111 100644
--- a/services/camera/libcameraservice/device3/BufferUtils.h
+++ b/services/camera/libcameraservice/device3/BufferUtils.h
@@ -154,9 +154,6 @@
}; // class BufferRecords
static const uint64_t BUFFER_ID_NO_BUFFER = 0;
-
- camera_buffer_status_t mapHidlBufferStatus(
- hardware::camera::device::V3_2::BufferStatus status);
} // namespace camera3
} // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 3742a17..992027a 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -65,6 +65,8 @@
#include "utils/TraceHFR.h"
#include "utils/CameraServiceProxyWrapper.h"
+#include "../common/hidl/HidlProviderInfo.h"
+
#include <algorithm>
#include <tuple>
@@ -112,164 +114,6 @@
return mId;
}
-status_t Camera3Device::initialize(sp<CameraProviderManager> manager, const String8& monitorTags) {
- ATRACE_CALL();
- Mutex::Autolock il(mInterfaceLock);
- Mutex::Autolock l(mLock);
-
- ALOGV("%s: Initializing HIDL device for camera %s", __FUNCTION__, mId.string());
- if (mStatus != STATUS_UNINITIALIZED) {
- CLOGE("Already initialized!");
- return INVALID_OPERATION;
- }
- if (manager == nullptr) return INVALID_OPERATION;
-
- sp<ICameraDeviceSession> session;
- ATRACE_BEGIN("CameraHal::openSession");
- status_t res = manager->openSession(mId.string(), this,
- /*out*/ &session);
- ATRACE_END();
- if (res != OK) {
- SET_ERR_L("Could not open camera session: %s (%d)", strerror(-res), res);
- return res;
- }
-
- res = manager->getCameraCharacteristics(mId.string(), mOverrideForPerfClass, &mDeviceInfo);
- if (res != OK) {
- SET_ERR_L("Could not retrieve camera characteristics: %s (%d)", strerror(-res), res);
- session->close();
- return res;
- }
- mSupportNativeZoomRatio = manager->supportNativeZoomRatio(mId.string());
-
- std::vector<std::string> physicalCameraIds;
- bool isLogical = manager->isLogicalCamera(mId.string(), &physicalCameraIds);
- if (isLogical) {
- for (auto& physicalId : physicalCameraIds) {
- // Do not override characteristics for physical cameras
- res = manager->getCameraCharacteristics(
- physicalId, /*overrideForPerfClass*/false, &mPhysicalDeviceInfoMap[physicalId]);
- if (res != OK) {
- SET_ERR_L("Could not retrieve camera %s characteristics: %s (%d)",
- physicalId.c_str(), strerror(-res), res);
- session->close();
- return res;
- }
-
- bool usePrecorrectArray =
- DistortionMapper::isDistortionSupported(mPhysicalDeviceInfoMap[physicalId]);
- if (usePrecorrectArray) {
- res = mDistortionMappers[physicalId].setupStaticInfo(
- mPhysicalDeviceInfoMap[physicalId]);
- if (res != OK) {
- SET_ERR_L("Unable to read camera %s's calibration fields for distortion "
- "correction", physicalId.c_str());
- session->close();
- return res;
- }
- }
-
- mZoomRatioMappers[physicalId] = ZoomRatioMapper(
- &mPhysicalDeviceInfoMap[physicalId],
- mSupportNativeZoomRatio, usePrecorrectArray);
-
- if (SessionConfigurationUtils::isUltraHighResolutionSensor(
- mPhysicalDeviceInfoMap[physicalId])) {
- mUHRCropAndMeteringRegionMappers[physicalId] =
- UHRCropAndMeteringRegionMapper(mPhysicalDeviceInfoMap[physicalId],
- usePrecorrectArray);
- }
- }
- }
-
- std::shared_ptr<RequestMetadataQueue> queue;
- auto requestQueueRet = session->getCaptureRequestMetadataQueue(
- [&queue](const auto& descriptor) {
- queue = std::make_shared<RequestMetadataQueue>(descriptor);
- if (!queue->isValid() || queue->availableToWrite() <= 0) {
- ALOGE("HAL returns empty request metadata fmq, not use it");
- queue = nullptr;
- // don't use the queue onwards.
- }
- });
- if (!requestQueueRet.isOk()) {
- ALOGE("Transaction error when getting request metadata fmq: %s, not use it",
- requestQueueRet.description().c_str());
- return DEAD_OBJECT;
- }
-
- std::unique_ptr<ResultMetadataQueue>& resQueue = mResultMetadataQueue;
- auto resultQueueRet = session->getCaptureResultMetadataQueue(
- [&resQueue](const auto& descriptor) {
- resQueue = std::make_unique<ResultMetadataQueue>(descriptor);
- if (!resQueue->isValid() || resQueue->availableToWrite() <= 0) {
- ALOGE("HAL returns empty result metadata fmq, not use it");
- resQueue = nullptr;
- // Don't use the resQueue onwards.
- }
- });
- if (!resultQueueRet.isOk()) {
- ALOGE("Transaction error when getting result metadata queue from camera session: %s",
- resultQueueRet.description().c_str());
- return DEAD_OBJECT;
- }
- IF_ALOGV() {
- session->interfaceChain([](
- ::android::hardware::hidl_vec<::android::hardware::hidl_string> interfaceChain) {
- ALOGV("Session interface chain:");
- for (const auto& iface : interfaceChain) {
- ALOGV(" %s", iface.c_str());
- }
- });
- }
-
- camera_metadata_entry bufMgrMode =
- mDeviceInfo.find(ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION);
- if (bufMgrMode.count > 0) {
- mUseHalBufManager = (bufMgrMode.data.u8[0] ==
- ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5);
- }
-
- camera_metadata_entry_t capabilities = mDeviceInfo.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
- for (size_t i = 0; i < capabilities.count; i++) {
- uint8_t capability = capabilities.data.u8[i];
- if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING) {
- mSupportOfflineProcessing = true;
- }
- }
-
- mInterface = new HalInterface(session, queue, mUseHalBufManager, mSupportOfflineProcessing);
- std::string providerType;
- mVendorTagId = manager->getProviderTagIdLocked(mId.string());
- mTagMonitor.initialize(mVendorTagId);
- if (!monitorTags.isEmpty()) {
- mTagMonitor.parseTagsToMonitor(String8(monitorTags));
- }
-
- // Metadata tags needs fixup for monochrome camera device version less
- // than 3.5.
- hardware::hidl_version maxVersion{0,0};
- res = manager->getHighestSupportedVersion(mId.string(), &maxVersion);
- if (res != OK) {
- ALOGE("%s: Error in getting camera device version id: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- return res;
- }
- int deviceVersion = HARDWARE_DEVICE_API_VERSION(
- maxVersion.get_major(), maxVersion.get_minor());
-
- bool isMonochrome = false;
- for (size_t i = 0; i < capabilities.count; i++) {
- uint8_t capability = capabilities.data.u8[i];
- if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME) {
- isMonochrome = true;
- }
- }
- mNeedFixupMonochromeTags = (isMonochrome && deviceVersion < CAMERA_DEVICE_API_VERSION_3_5);
-
- return initializeCommonLocked();
-}
-
status_t Camera3Device::initializeCommonLocked() {
/** Start up status tracker thread */
@@ -323,7 +167,7 @@
}
/** Start up request queue thread */
- mRequestThread = new RequestThread(
+ mRequestThread = createNewRequestThread(
this, mStatusTracker, mInterface, sessionParamKeys,
mUseHalBufManager, mSupportCameraMute);
res = mRequestThread->run(String8::format("C3Dev-%s-ReqQueue", mId.string()).string());
@@ -381,7 +225,8 @@
mRotateAndCropMappers.emplace(mId.c_str(), &mDeviceInfo);
}
- mInjectionMethods = new Camera3DeviceInjectionMethods(this);
+ // Hidl/AidlCamera3DeviceInjectionMethods
+ mInjectionMethods = createCamera3DeviceInjectionMethods(this);
return OK;
}
@@ -531,86 +376,16 @@
return measured;
}
-hardware::graphics::common::V1_0::PixelFormat Camera3Device::mapToPixelFormat(
- int frameworkFormat) {
- return (hardware::graphics::common::V1_0::PixelFormat) frameworkFormat;
-}
-
-DataspaceFlags Camera3Device::mapToHidlDataspace(
- android_dataspace dataSpace) {
- return dataSpace;
-}
-
-BufferUsageFlags Camera3Device::mapToConsumerUsage(
- uint64_t usage) {
- return usage;
-}
-
-StreamRotation Camera3Device::mapToStreamRotation(camera_stream_rotation_t rotation) {
- switch (rotation) {
- case CAMERA_STREAM_ROTATION_0:
- return StreamRotation::ROTATION_0;
- case CAMERA_STREAM_ROTATION_90:
- return StreamRotation::ROTATION_90;
- case CAMERA_STREAM_ROTATION_180:
- return StreamRotation::ROTATION_180;
- case CAMERA_STREAM_ROTATION_270:
- return StreamRotation::ROTATION_270;
- }
- ALOGE("%s: Unknown stream rotation %d", __FUNCTION__, rotation);
- return StreamRotation::ROTATION_0;
-}
-
-status_t Camera3Device::mapToStreamConfigurationMode(
- camera_stream_configuration_mode_t operationMode, StreamConfigurationMode *mode) {
- if (mode == nullptr) return BAD_VALUE;
- if (operationMode < CAMERA_VENDOR_STREAM_CONFIGURATION_MODE_START) {
- switch(operationMode) {
- case CAMERA_STREAM_CONFIGURATION_NORMAL_MODE:
- *mode = StreamConfigurationMode::NORMAL_MODE;
- break;
- case CAMERA_STREAM_CONFIGURATION_CONSTRAINED_HIGH_SPEED_MODE:
- *mode = StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE;
- break;
- default:
- ALOGE("%s: Unknown stream configuration mode %d", __FUNCTION__, operationMode);
- return BAD_VALUE;
- }
- } else {
- *mode = static_cast<StreamConfigurationMode>(operationMode);
- }
- return OK;
-}
-
-int Camera3Device::mapToFrameworkFormat(
- hardware::graphics::common::V1_0::PixelFormat pixelFormat) {
- return static_cast<uint32_t>(pixelFormat);
-}
-
-android_dataspace Camera3Device::mapToFrameworkDataspace(
- DataspaceFlags dataSpace) {
- return static_cast<android_dataspace>(dataSpace);
-}
-
-uint64_t Camera3Device::mapConsumerToFrameworkUsage(
- BufferUsageFlags usage) {
- return usage;
-}
-
-uint64_t Camera3Device::mapProducerToFrameworkUsage(
- BufferUsageFlags usage) {
- return usage;
-}
-
-ssize_t Camera3Device::getJpegBufferSize(uint32_t width, uint32_t height) const {
+ssize_t Camera3Device::getJpegBufferSize(const CameraMetadata &info, uint32_t width,
+ uint32_t height) const {
// Get max jpeg size (area-wise) for default sensor pixel mode
camera3::Size maxDefaultJpegResolution =
- SessionConfigurationUtils::getMaxJpegResolution(mDeviceInfo,
+ SessionConfigurationUtils::getMaxJpegResolution(info,
/*isUltraHighResolutionSensor*/false);
// Get max jpeg size (area-wise) for max resolution sensor pixel mode / 0 if
// not ultra high res sensor
camera3::Size uhrMaxJpegResolution =
- SessionConfigurationUtils::getMaxJpegResolution(mDeviceInfo,
+ SessionConfigurationUtils::getMaxJpegResolution(info,
/*isUltraHighResolution*/true);
if (maxDefaultJpegResolution.width == 0) {
ALOGE("%s: Camera %s: Can't find valid available jpeg sizes in static metadata!",
@@ -626,7 +401,7 @@
// Get max jpeg buffer size
ssize_t maxJpegBufferSize = 0;
- camera_metadata_ro_entry jpegBufMaxSize = mDeviceInfo.find(ANDROID_JPEG_MAX_SIZE);
+ camera_metadata_ro_entry jpegBufMaxSize = info.find(ANDROID_JPEG_MAX_SIZE);
if (jpegBufMaxSize.count == 0) {
ALOGE("%s: Camera %s: Can't find maximum JPEG size in static metadata!", __FUNCTION__,
mId.string());
@@ -656,9 +431,9 @@
return jpegBufferSize;
}
-ssize_t Camera3Device::getPointCloudBufferSize() const {
+ssize_t Camera3Device::getPointCloudBufferSize(const CameraMetadata &info) const {
const int FLOATS_PER_POINT=4;
- camera_metadata_ro_entry maxPointCount = mDeviceInfo.find(ANDROID_DEPTH_MAX_DEPTH_SAMPLES);
+ camera_metadata_ro_entry maxPointCount = info.find(ANDROID_DEPTH_MAX_DEPTH_SAMPLES);
if (maxPointCount.count == 0) {
ALOGE("%s: Camera %s: Can't find maximum depth point cloud size in static metadata!",
__FUNCTION__, mId.string());
@@ -669,14 +444,14 @@
return maxBytesForPointCloud;
}
-ssize_t Camera3Device::getRawOpaqueBufferSize(int32_t width, int32_t height,
- bool maxResolution) const {
+ssize_t Camera3Device::getRawOpaqueBufferSize(const CameraMetadata &info, int32_t width,
+ int32_t height, bool maxResolution) const {
const int PER_CONFIGURATION_SIZE = 3;
const int WIDTH_OFFSET = 0;
const int HEIGHT_OFFSET = 1;
const int SIZE_OFFSET = 2;
camera_metadata_ro_entry rawOpaqueSizes =
- mDeviceInfo.find(
+ info.find(
camera3::SessionConfigurationUtils::getAppropriateModeTag(
ANDROID_SENSOR_OPAQUE_RAW_SIZE,
maxResolution));
@@ -1043,186 +818,6 @@
return res;
}
-hardware::Return<void> Camera3Device::requestStreamBuffers(
- const hardware::hidl_vec<hardware::camera::device::V3_5::BufferRequest>& bufReqs,
- requestStreamBuffers_cb _hidl_cb) {
- RequestBufferStates states {
- mId, mRequestBufferInterfaceLock, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder,
- *this, *mInterface, *this};
- camera3::requestStreamBuffers(states, bufReqs, _hidl_cb);
- return hardware::Void();
-}
-
-hardware::Return<void> Camera3Device::returnStreamBuffers(
- const hardware::hidl_vec<hardware::camera::device::V3_2::StreamBuffer>& buffers) {
- ReturnBufferStates states {
- mId, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder, *mInterface};
- camera3::returnStreamBuffers(states, buffers);
- return hardware::Void();
-}
-
-hardware::Return<void> Camera3Device::processCaptureResult_3_4(
- const hardware::hidl_vec<
- hardware::camera::device::V3_4::CaptureResult>& results) {
- // Ideally we should grab mLock, but that can lead to deadlock, and
- // it's not super important to get up to date value of mStatus for this
- // warning print, hence skipping the lock here
- if (mStatus == STATUS_ERROR) {
- // Per API contract, HAL should act as closed after device error
- // But mStatus can be set to error by framework as well, so just log
- // a warning here.
- ALOGW("%s: received capture result in error state.", __FUNCTION__);
- }
-
- sp<NotificationListener> listener;
- {
- std::lock_guard<std::mutex> l(mOutputLock);
- listener = mListener.promote();
- }
-
- if (mProcessCaptureResultLock.tryLock() != OK) {
- // This should never happen; it indicates a wrong client implementation
- // that doesn't follow the contract. But, we can be tolerant here.
- ALOGE("%s: callback overlapped! waiting 1s...",
- __FUNCTION__);
- if (mProcessCaptureResultLock.timedLock(1000000000 /* 1s */) != OK) {
- ALOGE("%s: cannot acquire lock in 1s, dropping results",
- __FUNCTION__);
- // really don't know what to do, so bail out.
- return hardware::Void();
- }
- }
- CaptureOutputStates states {
- mId,
- mInFlightLock, mLastCompletedRegularFrameNumber,
- mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
- mInFlightMap, mOutputLock, mResultQueue, mResultSignal,
- mNextShutterFrameNumber,
- mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
- mNextResultFrameNumber,
- mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
- mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
- mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
- mResultMetadataQueue, mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
- mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
- *mInterface, mLegacyClient
- };
-
- for (const auto& result : results) {
- processOneCaptureResultLocked(states, result.v3_2, result.physicalCameraMetadata);
- }
- mProcessCaptureResultLock.unlock();
- return hardware::Void();
-}
-
-// Only one processCaptureResult should be called at a time, so
-// the locks won't block. The locks are present here simply to enforce this.
-hardware::Return<void> Camera3Device::processCaptureResult(
- const hardware::hidl_vec<
- hardware::camera::device::V3_2::CaptureResult>& results) {
- hardware::hidl_vec<hardware::camera::device::V3_4::PhysicalCameraMetadata> noPhysMetadata;
-
- // Ideally we should grab mLock, but that can lead to deadlock, and
- // it's not super important to get up to date value of mStatus for this
- // warning print, hence skipping the lock here
- if (mStatus == STATUS_ERROR) {
- // Per API contract, HAL should act as closed after device error
- // But mStatus can be set to error by framework as well, so just log
- // a warning here.
- ALOGW("%s: received capture result in error state.", __FUNCTION__);
- }
-
- sp<NotificationListener> listener;
- {
- std::lock_guard<std::mutex> l(mOutputLock);
- listener = mListener.promote();
- }
-
- if (mProcessCaptureResultLock.tryLock() != OK) {
- // This should never happen; it indicates a wrong client implementation
- // that doesn't follow the contract. But, we can be tolerant here.
- ALOGE("%s: callback overlapped! waiting 1s...",
- __FUNCTION__);
- if (mProcessCaptureResultLock.timedLock(1000000000 /* 1s */) != OK) {
- ALOGE("%s: cannot acquire lock in 1s, dropping results",
- __FUNCTION__);
- // really don't know what to do, so bail out.
- return hardware::Void();
- }
- }
-
- CaptureOutputStates states {
- mId,
- mInFlightLock, mLastCompletedRegularFrameNumber,
- mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
- mInFlightMap, mOutputLock, mResultQueue, mResultSignal,
- mNextShutterFrameNumber,
- mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
- mNextResultFrameNumber,
- mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
- mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
- mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
- mResultMetadataQueue, mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
- mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
- *mInterface, mLegacyClient
- };
-
- for (const auto& result : results) {
- processOneCaptureResultLocked(states, result, noPhysMetadata);
- }
- mProcessCaptureResultLock.unlock();
- return hardware::Void();
-}
-
-hardware::Return<void> Camera3Device::notify(
- const hardware::hidl_vec<hardware::camera::device::V3_2::NotifyMsg>& msgs) {
- return notifyHelper<hardware::camera::device::V3_2::NotifyMsg>(msgs);
-}
-
-hardware::Return<void> Camera3Device::notify_3_8(
- const hardware::hidl_vec<hardware::camera::device::V3_8::NotifyMsg>& msgs) {
- return notifyHelper<hardware::camera::device::V3_8::NotifyMsg>(msgs);
-}
-
-template<typename NotifyMsgType>
-hardware::Return<void> Camera3Device::notifyHelper(const hardware::hidl_vec<NotifyMsgType>& msgs) {
- // Ideally we should grab mLock, but that can lead to deadlock, and
- // it's not super important to get up to date value of mStatus for this
- // warning print, hence skipping the lock here
- if (mStatus == STATUS_ERROR) {
- // Per API contract, HAL should act as closed after device error
- // But mStatus can be set to error by framework as well, so just log
- // a warning here.
- ALOGW("%s: received notify message in error state.", __FUNCTION__);
- }
-
- sp<NotificationListener> listener;
- {
- std::lock_guard<std::mutex> l(mOutputLock);
- listener = mListener.promote();
- }
-
- CaptureOutputStates states {
- mId,
- mInFlightLock, mLastCompletedRegularFrameNumber,
- mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
- mInFlightMap, mOutputLock, mResultQueue, mResultSignal,
- mNextShutterFrameNumber,
- mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
- mNextResultFrameNumber,
- mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
- mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
- mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
- mResultMetadataQueue, mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
- mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
- *mInterface, mLegacyClient
- };
- for (const auto& msg : msgs) {
- camera3::notify(states, msg);
- }
- return hardware::Void();
-}
-
status_t Camera3Device::captureList(const List<const PhysicalCameraSettingsList> &requestsList,
const std::list<const SurfaceMap> &surfaceMaps,
int64_t *lastFrameNumber) {
@@ -1383,7 +978,7 @@
const String8& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
std::vector<int> *surfaceIds, int streamSetId, bool isShared, bool isMultiResolution,
- uint64_t consumerUsage) {
+ uint64_t consumerUsage, int dynamicRangeProfile) {
ATRACE_CALL();
if (consumer == nullptr) {
@@ -1396,7 +991,7 @@
return createStream(consumers, /*hasDeferredConsumer*/ false, width, height,
format, dataSpace, rotation, id, physicalCameraId, sensorPixelModesUsed, surfaceIds,
- streamSetId, isShared, isMultiResolution, consumerUsage);
+ streamSetId, isShared, isMultiResolution, consumerUsage, dynamicRangeProfile);
}
static bool isRawFormat(int format) {
@@ -1416,7 +1011,7 @@
android_dataspace dataSpace, camera_stream_rotation_t rotation, int *id,
const String8& physicalCameraId, const std::unordered_set<int32_t> &sensorPixelModesUsed,
std::vector<int> *surfaceIds, int streamSetId, bool isShared, bool isMultiResolution,
- uint64_t consumerUsage) {
+ uint64_t consumerUsage, int dynamicRangeProfile) {
ATRACE_CALL();
Mutex::Autolock il(mInterfaceLock);
@@ -1477,7 +1072,7 @@
if (format == HAL_PIXEL_FORMAT_BLOB) {
ssize_t blobBufferSize;
if (dataSpace == HAL_DATASPACE_DEPTH) {
- blobBufferSize = getPointCloudBufferSize();
+ blobBufferSize = getPointCloudBufferSize(infoPhysical(physicalCameraId));
if (blobBufferSize <= 0) {
SET_ERR_L("Invalid point cloud buffer size %zd", blobBufferSize);
return BAD_VALUE;
@@ -1485,7 +1080,7 @@
} else if (dataSpace == static_cast<android_dataspace>(HAL_DATASPACE_JPEG_APP_SEGMENTS)) {
blobBufferSize = width * height;
} else {
- blobBufferSize = getJpegBufferSize(width, height);
+ blobBufferSize = getJpegBufferSize(infoPhysical(physicalCameraId), width, height);
if (blobBufferSize <= 0) {
SET_ERR_L("Invalid jpeg buffer size %zd", blobBufferSize);
return BAD_VALUE;
@@ -1494,12 +1089,13 @@
newStream = new Camera3OutputStream(mNextStreamId, consumers[0],
width, height, blobBufferSize, format, dataSpace, rotation,
mTimestampOffset, physicalCameraId, sensorPixelModesUsed, streamSetId,
- isMultiResolution);
+ isMultiResolution, dynamicRangeProfile);
} else if (format == HAL_PIXEL_FORMAT_RAW_OPAQUE) {
bool maxResolution =
sensorPixelModesUsed.find(ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION) !=
sensorPixelModesUsed.end();
- ssize_t rawOpaqueBufferSize = getRawOpaqueBufferSize(width, height, maxResolution);
+ ssize_t rawOpaqueBufferSize = getRawOpaqueBufferSize(infoPhysical(physicalCameraId), width,
+ height, maxResolution);
if (rawOpaqueBufferSize <= 0) {
SET_ERR_L("Invalid RAW opaque buffer size %zd", rawOpaqueBufferSize);
return BAD_VALUE;
@@ -1507,22 +1103,22 @@
newStream = new Camera3OutputStream(mNextStreamId, consumers[0],
width, height, rawOpaqueBufferSize, format, dataSpace, rotation,
mTimestampOffset, physicalCameraId, sensorPixelModesUsed, streamSetId,
- isMultiResolution);
+ isMultiResolution, dynamicRangeProfile);
} else if (isShared) {
newStream = new Camera3SharedOutputStream(mNextStreamId, consumers,
width, height, format, consumerUsage, dataSpace, rotation,
mTimestampOffset, physicalCameraId, sensorPixelModesUsed, streamSetId,
- mUseHalBufManager);
+ mUseHalBufManager, dynamicRangeProfile);
} else if (consumers.size() == 0 && hasDeferredConsumer) {
newStream = new Camera3OutputStream(mNextStreamId,
width, height, format, consumerUsage, dataSpace, rotation,
mTimestampOffset, physicalCameraId, sensorPixelModesUsed, streamSetId,
- isMultiResolution);
+ isMultiResolution, dynamicRangeProfile);
} else {
newStream = new Camera3OutputStream(mNextStreamId, consumers[0],
width, height, format, dataSpace, rotation,
mTimestampOffset, physicalCameraId, sensorPixelModesUsed, streamSetId,
- isMultiResolution);
+ isMultiResolution, dynamicRangeProfile);
}
size_t consumerCount = consumers.size();
@@ -1609,6 +1205,7 @@
streamInfo->originalFormat = stream->getOriginalFormat();
streamInfo->dataSpaceOverridden = stream->isDataSpaceOverridden();
streamInfo->originalDataSpace = stream->getOriginalDataSpace();
+ streamInfo->dynamicRangeProfile = stream->getDynamicRangeProfile();
return OK;
}
@@ -2221,7 +1818,8 @@
streamStats.emplace_back(stream->getWidth(), stream->getHeight(),
stream->getFormat(), stream->getDataSpace(), usage,
stream->getMaxHalBuffers(),
- stream->getMaxTotalBuffers() - stream->getMaxHalBuffers());
+ stream->getMaxTotalBuffers() - stream->getMaxHalBuffers(),
+ stream->getDynamicRangeProfile());
}
}
}
@@ -2730,7 +2328,8 @@
// always occupy the initial entry.
if (outputStream->data_space == HAL_DATASPACE_V0_JFIF) {
bufferSizes[k] = static_cast<uint32_t>(
- getJpegBufferSize(outputStream->width, outputStream->height));
+ getJpegBufferSize(infoPhysical(String8(outputStream->physical_camera_id)),
+ outputStream->width, outputStream->height));
} else if (outputStream->data_space ==
static_cast<android_dataspace>(HAL_DATASPACE_JPEG_APP_SEGMENTS)) {
bufferSizes[k] = outputStream->width * outputStream->height;
@@ -3130,702 +2729,6 @@
* HalInterface inner class methods
*/
-Camera3Device::HalInterface::HalInterface(
- sp<ICameraDeviceSession> &session,
- std::shared_ptr<RequestMetadataQueue> queue,
- bool useHalBufManager, bool supportOfflineProcessing) :
- mHidlSession(session),
- mRequestMetadataQueue(queue),
- mUseHalBufManager(useHalBufManager),
- mIsReconfigurationQuerySupported(true),
- 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;
- }
- auto castResult_3_5 = device::V3_5::ICameraDeviceSession::castFrom(mHidlSession);
- if (castResult_3_5.isOk()) {
- mHidlSession_3_5 = castResult_3_5;
- }
- auto castResult_3_4 = device::V3_4::ICameraDeviceSession::castFrom(mHidlSession);
- if (castResult_3_4.isOk()) {
- mHidlSession_3_4 = castResult_3_4;
- }
- auto castResult_3_3 = device::V3_3::ICameraDeviceSession::castFrom(mHidlSession);
- if (castResult_3_3.isOk()) {
- mHidlSession_3_3 = castResult_3_3;
- }
-}
-
-Camera3Device::HalInterface::HalInterface() :
- mUseHalBufManager(false),
- mSupportOfflineProcessing(false) {}
-
-Camera3Device::HalInterface::HalInterface(const HalInterface& other) :
- mHidlSession(other.mHidlSession),
- mRequestMetadataQueue(other.mRequestMetadataQueue),
- mUseHalBufManager(other.mUseHalBufManager),
- mSupportOfflineProcessing(other.mSupportOfflineProcessing) {}
-
-bool Camera3Device::HalInterface::valid() {
- return (mHidlSession != nullptr);
-}
-
-void Camera3Device::HalInterface::clear() {
- mHidlSession_3_7.clear();
- mHidlSession_3_6.clear();
- mHidlSession_3_5.clear();
- mHidlSession_3_4.clear();
- mHidlSession_3_3.clear();
- mHidlSession.clear();
-}
-
-status_t Camera3Device::HalInterface::constructDefaultRequestSettings(
- camera_request_template_t templateId,
- /*out*/ camera_metadata_t **requestTemplate) {
- ATRACE_NAME("CameraHal::constructDefaultRequestSettings");
- if (!valid()) return INVALID_OPERATION;
- status_t res = OK;
-
- common::V1_0::Status status;
-
- auto requestCallback = [&status, &requestTemplate]
- (common::V1_0::Status s, const device::V3_2::CameraMetadata& request) {
- status = s;
- if (status == common::V1_0::Status::OK) {
- const camera_metadata *r =
- reinterpret_cast<const camera_metadata_t*>(request.data());
- size_t expectedSize = request.size();
- int ret = validate_camera_metadata_structure(r, &expectedSize);
- if (ret == OK || ret == CAMERA_METADATA_VALIDATION_SHIFTED) {
- *requestTemplate = clone_camera_metadata(r);
- if (*requestTemplate == nullptr) {
- ALOGE("%s: Unable to clone camera metadata received from HAL",
- __FUNCTION__);
- status = common::V1_0::Status::INTERNAL_ERROR;
- }
- } else {
- ALOGE("%s: Malformed camera metadata received from HAL", __FUNCTION__);
- status = common::V1_0::Status::INTERNAL_ERROR;
- }
- }
- };
- hardware::Return<void> err;
- RequestTemplate id;
- switch (templateId) {
- case CAMERA_TEMPLATE_PREVIEW:
- id = RequestTemplate::PREVIEW;
- break;
- case CAMERA_TEMPLATE_STILL_CAPTURE:
- id = RequestTemplate::STILL_CAPTURE;
- break;
- case CAMERA_TEMPLATE_VIDEO_RECORD:
- id = RequestTemplate::VIDEO_RECORD;
- break;
- case CAMERA_TEMPLATE_VIDEO_SNAPSHOT:
- id = RequestTemplate::VIDEO_SNAPSHOT;
- break;
- case CAMERA_TEMPLATE_ZERO_SHUTTER_LAG:
- id = RequestTemplate::ZERO_SHUTTER_LAG;
- break;
- case CAMERA_TEMPLATE_MANUAL:
- id = RequestTemplate::MANUAL;
- break;
- default:
- // Unknown template ID, or this HAL is too old to support it
- return BAD_VALUE;
- }
- err = mHidlSession->constructDefaultRequestSettings(id, requestCallback);
-
- if (!err.isOk()) {
- ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
- res = DEAD_OBJECT;
- } else {
- res = CameraProviderManager::mapToStatusT(status);
- }
-
- return res;
-}
-
-bool Camera3Device::HalInterface::isReconfigurationRequired(CameraMetadata& oldSessionParams,
- CameraMetadata& newSessionParams) {
- // We do reconfiguration by default;
- bool ret = true;
- if ((mHidlSession_3_5 != nullptr) && mIsReconfigurationQuerySupported) {
- android::hardware::hidl_vec<uint8_t> oldParams, newParams;
- camera_metadata_t* oldSessioMeta = const_cast<camera_metadata_t*>(
- oldSessionParams.getAndLock());
- camera_metadata_t* newSessioMeta = const_cast<camera_metadata_t*>(
- newSessionParams.getAndLock());
- oldParams.setToExternal(reinterpret_cast<uint8_t*>(oldSessioMeta),
- get_camera_metadata_size(oldSessioMeta));
- newParams.setToExternal(reinterpret_cast<uint8_t*>(newSessioMeta),
- get_camera_metadata_size(newSessioMeta));
- hardware::camera::common::V1_0::Status callStatus;
- bool required;
- auto hidlCb = [&callStatus, &required] (hardware::camera::common::V1_0::Status s,
- bool requiredFlag) {
- callStatus = s;
- required = requiredFlag;
- };
- auto err = mHidlSession_3_5->isReconfigurationRequired(oldParams, newParams, hidlCb);
- oldSessionParams.unlock(oldSessioMeta);
- newSessionParams.unlock(newSessioMeta);
- if (err.isOk()) {
- switch (callStatus) {
- case hardware::camera::common::V1_0::Status::OK:
- ret = required;
- break;
- case hardware::camera::common::V1_0::Status::METHOD_NOT_SUPPORTED:
- mIsReconfigurationQuerySupported = false;
- ret = true;
- break;
- default:
- ALOGV("%s: Reconfiguration query failed: %d", __FUNCTION__, callStatus);
- ret = true;
- }
- } else {
- ALOGE("%s: Unexpected binder error: %s", __FUNCTION__, err.description().c_str());
- ret = true;
- }
- }
-
- return ret;
-}
-
-status_t Camera3Device::HalInterface::configureStreams(const camera_metadata_t *sessionParams,
- camera_stream_configuration *config, const std::vector<uint32_t>& bufferSizes) {
- ATRACE_NAME("CameraHal::configureStreams");
- 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);
- cam3stream->setBufferFreedListener(this);
- int streamId = cam3stream->getId();
- StreamType streamType;
- switch (src->stream_type) {
- case CAMERA_STREAM_OUTPUT:
- streamType = StreamType::OUTPUT;
- break;
- case CAMERA_STREAM_INPUT:
- streamType = StreamType::INPUT;
- break;
- default:
- ALOGE("%s: Stream %d: Unsupported stream type %d",
- __FUNCTION__, streamId, config->streams[i]->stream_type);
- return BAD_VALUE;
- }
- dst3_2.id = streamId;
- dst3_2.streamType = streamType;
- dst3_2.width = src->width;
- dst3_2.height = src->height;
- dst3_2.usage = mapToConsumerUsage(cam3stream->getUsage());
- dst3_2.rotation = mapToStreamRotation((camera_stream_rotation_t) src->rotation);
- // For HidlSession version 3.5 or newer, the format and dataSpace sent
- // to HAL are original, not the overridden ones.
- if (mHidlSession_3_5 != nullptr) {
- dst3_2.format = mapToPixelFormat(cam3stream->isFormatOverridden() ?
- cam3stream->getOriginalFormat() : src->format);
- dst3_2.dataSpace = mapToHidlDataspace(cam3stream->isDataSpaceOverridden() ?
- cam3stream->getOriginalDataSpace() : src->data_space);
- } else {
- dst3_2.format = mapToPixelFormat(src->format);
- dst3_2.dataSpace = mapToHidlDataspace(src->data_space);
- }
- dst3_4.v3_2 = dst3_2;
- dst3_4.bufferSize = bufferSizes[i];
- if (src->physical_camera_id != nullptr) {
- dst3_4.physicalCameraId = src->physical_camera_id;
- }
- dst3_7.v3_4 = dst3_4;
- dst3_7.groupId = cam3stream->getHalStreamGroupId();
- dst3_7.sensorPixelModesUsed.resize(src->sensor_pixel_modes_used.size());
- size_t j = 0;
- for (int mode : src->sensor_pixel_modes_used) {
- dst3_7.sensorPixelModesUsed[j++] =
- static_cast<CameraMetadataEnumAndroidSensorPixelMode>(mode);
- }
- activeStreams.insert(streamId);
- // Create Buffer ID map if necessary
- mBufferRecords.tryCreateBufferCache(streamId);
- }
- // remove BufferIdMap for deleted streams
- mBufferRecords.removeInactiveBufferCaches(activeStreams);
-
- StreamConfigurationMode operationMode;
- res = mapToStreamConfigurationMode(
- (camera_stream_configuration_mode_t) config->operation_mode,
- /*out*/ &operationMode);
- if (res != OK) {
- return res;
- }
- requestedConfiguration3_2.operationMode = operationMode;
- requestedConfiguration3_4.operationMode = operationMode;
- requestedConfiguration3_7.operationMode = operationMode;
- size_t sessionParamSize = get_camera_metadata_size(sessionParams);
- requestedConfiguration3_4.sessionParams.setToExternal(
- reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(sessionParams)),
- sessionParamSize);
- requestedConfiguration3_7.operationMode = operationMode;
- requestedConfiguration3_7.sessionParams.setToExternal(
- reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(sessionParams)),
- sessionParamSize);
-
- // Invoke configureStreams
- device::V3_3::HalStreamConfiguration finalConfiguration;
- device::V3_4::HalStreamConfiguration finalConfiguration3_4;
- device::V3_6::HalStreamConfiguration finalConfiguration3_6;
- common::V1_0::Status status;
-
- auto configStream34Cb = [&status, &finalConfiguration3_4]
- (common::V1_0::Status s, const device::V3_4::HalStreamConfiguration& halConfiguration) {
- finalConfiguration3_4 = halConfiguration;
- status = s;
- };
-
- auto configStream36Cb = [&status, &finalConfiguration3_6]
- (common::V1_0::Status s, const device::V3_6::HalStreamConfiguration& halConfiguration) {
- finalConfiguration3_6 = halConfiguration;
- status = s;
- };
-
- auto postprocConfigStream34 = [&finalConfiguration, &finalConfiguration3_4]
- (hardware::Return<void>& err) -> status_t {
- if (!err.isOk()) {
- ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
- return DEAD_OBJECT;
- }
- finalConfiguration.streams.resize(finalConfiguration3_4.streams.size());
- for (size_t i = 0; i < finalConfiguration3_4.streams.size(); i++) {
- finalConfiguration.streams[i] = finalConfiguration3_4.streams[i].v3_3;
- }
- return OK;
- };
-
- auto postprocConfigStream36 = [&finalConfiguration, &finalConfiguration3_6]
- (hardware::Return<void>& err) -> status_t {
- if (!err.isOk()) {
- ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
- return DEAD_OBJECT;
- }
- finalConfiguration.streams.resize(finalConfiguration3_6.streams.size());
- for (size_t i = 0; i < finalConfiguration3_6.streams.size(); i++) {
- finalConfiguration.streams[i] = finalConfiguration3_6.streams[i].v3_4.v3_3;
- }
- return OK;
- };
-
- // See which version of HAL we have
- 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;
- requestedConfiguration3_5.streamConfigCounter = mNextStreamConfigCounter++;
- auto err = mHidlSession_3_6->configureStreams_3_6(
- requestedConfiguration3_5, configStream36Cb);
- res = postprocConfigStream36(err);
- if (res != OK) {
- return res;
- }
- } else if (mHidlSession_3_5 != nullptr) {
- ALOGV("%s: v3.5 device found", __FUNCTION__);
- device::V3_5::StreamConfiguration requestedConfiguration3_5;
- requestedConfiguration3_5.v3_4 = requestedConfiguration3_4;
- requestedConfiguration3_5.streamConfigCounter = mNextStreamConfigCounter++;
- auto err = mHidlSession_3_5->configureStreams_3_5(
- requestedConfiguration3_5, configStream34Cb);
- res = postprocConfigStream34(err);
- if (res != OK) {
- return res;
- }
- } else if (mHidlSession_3_4 != nullptr) {
- // We do; use v3.4 for the call
- ALOGV("%s: v3.4 device found", __FUNCTION__);
- auto err = mHidlSession_3_4->configureStreams_3_4(
- requestedConfiguration3_4, configStream34Cb);
- res = postprocConfigStream34(err);
- if (res != OK) {
- return res;
- }
- } else if (mHidlSession_3_3 != nullptr) {
- // We do; use v3.3 for the call
- ALOGV("%s: v3.3 device found", __FUNCTION__);
- auto err = mHidlSession_3_3->configureStreams_3_3(requestedConfiguration3_2,
- [&status, &finalConfiguration]
- (common::V1_0::Status s, const device::V3_3::HalStreamConfiguration& halConfiguration) {
- finalConfiguration = halConfiguration;
- status = s;
- });
- if (!err.isOk()) {
- ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
- return DEAD_OBJECT;
- }
- } else {
- // We don't; use v3.2 call and construct a v3.3 HalStreamConfiguration
- ALOGV("%s: v3.2 device found", __FUNCTION__);
- HalStreamConfiguration finalConfiguration_3_2;
- auto err = mHidlSession->configureStreams(requestedConfiguration3_2,
- [&status, &finalConfiguration_3_2]
- (common::V1_0::Status s, const HalStreamConfiguration& halConfiguration) {
- finalConfiguration_3_2 = halConfiguration;
- status = s;
- });
- if (!err.isOk()) {
- ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
- return DEAD_OBJECT;
- }
- finalConfiguration.streams.resize(finalConfiguration_3_2.streams.size());
- for (size_t i = 0; i < finalConfiguration_3_2.streams.size(); i++) {
- finalConfiguration.streams[i].v3_2 = finalConfiguration_3_2.streams[i];
- finalConfiguration.streams[i].overrideDataSpace =
- requestedConfiguration3_2.streams[i].dataSpace;
- }
- }
-
- if (status != common::V1_0::Status::OK ) {
- return CameraProviderManager::mapToStatusT(status);
- }
-
- // And convert output stream configuration from HIDL
-
- for (size_t i = 0; i < config->num_streams; i++) {
- camera3::camera_stream_t *dst = config->streams[i];
- int streamId = Camera3Stream::cast(dst)->getId();
-
- // Start scan at i, with the assumption that the stream order matches
- size_t realIdx = i;
- bool found = false;
- size_t halStreamCount = finalConfiguration.streams.size();
- for (size_t idx = 0; idx < halStreamCount; idx++) {
- if (finalConfiguration.streams[realIdx].v3_2.id == streamId) {
- found = true;
- break;
- }
- realIdx = (realIdx >= halStreamCount - 1) ? 0 : realIdx + 1;
- }
- if (!found) {
- ALOGE("%s: Stream %d not found in stream configuration response from HAL",
- __FUNCTION__, streamId);
- return INVALID_OPERATION;
- }
- device::V3_3::HalStream &src = finalConfiguration.streams[realIdx];
- device::V3_6::HalStream &src_36 = finalConfiguration3_6.streams[realIdx];
-
- Camera3Stream* dstStream = Camera3Stream::cast(dst);
- int overrideFormat = mapToFrameworkFormat(src.v3_2.overrideFormat);
- android_dataspace overrideDataSpace = mapToFrameworkDataspace(src.overrideDataSpace);
-
- if (mHidlSession_3_6 != nullptr) {
- dstStream->setOfflineProcessingSupport(src_36.supportOffline);
- }
-
- if (dstStream->getOriginalFormat() != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
- dstStream->setFormatOverride(false);
- dstStream->setDataSpaceOverride(false);
- if (dst->format != overrideFormat) {
- ALOGE("%s: Stream %d: Format override not allowed for format 0x%x", __FUNCTION__,
- streamId, dst->format);
- }
- if (dst->data_space != overrideDataSpace) {
- ALOGE("%s: Stream %d: DataSpace override not allowed for format 0x%x", __FUNCTION__,
- streamId, dst->format);
- }
- } else {
- bool needFormatOverride =
- requestedConfiguration3_2.streams[i].format != src.v3_2.overrideFormat;
- bool needDataspaceOverride =
- requestedConfiguration3_2.streams[i].dataSpace != src.overrideDataSpace;
- // Override allowed with IMPLEMENTATION_DEFINED
- dstStream->setFormatOverride(needFormatOverride);
- dstStream->setDataSpaceOverride(needDataspaceOverride);
- dst->format = overrideFormat;
- dst->data_space = overrideDataSpace;
- }
-
- if (dst->stream_type == CAMERA_STREAM_INPUT) {
- if (src.v3_2.producerUsage != 0) {
- ALOGE("%s: Stream %d: INPUT streams must have 0 for producer usage",
- __FUNCTION__, streamId);
- return INVALID_OPERATION;
- }
- dstStream->setUsage(
- mapConsumerToFrameworkUsage(src.v3_2.consumerUsage));
- } else {
- // OUTPUT
- if (src.v3_2.consumerUsage != 0) {
- ALOGE("%s: Stream %d: OUTPUT streams must have 0 for consumer usage",
- __FUNCTION__, streamId);
- return INVALID_OPERATION;
- }
- dstStream->setUsage(
- mapProducerToFrameworkUsage(src.v3_2.producerUsage));
- }
- dst->max_buffers = src.v3_2.maxBuffers;
- }
-
- return res;
-}
-
-status_t Camera3Device::HalInterface::configureInjectedStreams(
- const camera_metadata_t* sessionParams, camera_stream_configuration* config,
- const std::vector<uint32_t>& bufferSizes,
- const CameraMetadata& cameraCharacteristics) {
- ATRACE_NAME("InjectionCameraHal::configureStreams");
- if (!valid()) return INVALID_OPERATION;
- status_t res = OK;
-
- if (config->input_is_multi_resolution) {
- ALOGE("%s: Injection 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);
- cam3stream->setBufferFreedListener(this);
- int streamId = cam3stream->getId();
- StreamType streamType;
- switch (src->stream_type) {
- case CAMERA_STREAM_OUTPUT:
- streamType = StreamType::OUTPUT;
- break;
- case CAMERA_STREAM_INPUT:
- streamType = StreamType::INPUT;
- break;
- default:
- ALOGE("%s: Stream %d: Unsupported stream type %d", __FUNCTION__,
- streamId, config->streams[i]->stream_type);
- return BAD_VALUE;
- }
- dst3_2.id = streamId;
- dst3_2.streamType = streamType;
- dst3_2.width = src->width;
- dst3_2.height = src->height;
- dst3_2.usage = mapToConsumerUsage(cam3stream->getUsage());
- dst3_2.rotation =
- mapToStreamRotation((camera_stream_rotation_t)src->rotation);
- // For HidlSession version 3.5 or newer, the format and dataSpace sent
- // to HAL are original, not the overridden ones.
- if (mHidlSession_3_5 != nullptr) {
- dst3_2.format = mapToPixelFormat(cam3stream->isFormatOverridden()
- ? cam3stream->getOriginalFormat()
- : src->format);
- dst3_2.dataSpace =
- mapToHidlDataspace(cam3stream->isDataSpaceOverridden()
- ? cam3stream->getOriginalDataSpace()
- : src->data_space);
- } else {
- dst3_2.format = mapToPixelFormat(src->format);
- dst3_2.dataSpace = mapToHidlDataspace(src->data_space);
- }
- dst3_4.v3_2 = dst3_2;
- dst3_4.bufferSize = bufferSizes[i];
- if (src->physical_camera_id != nullptr) {
- dst3_4.physicalCameraId = src->physical_camera_id;
- }
- dst3_7.v3_4 = dst3_4;
- dst3_7.groupId = cam3stream->getHalStreamGroupId();
- dst3_7.sensorPixelModesUsed.resize(src->sensor_pixel_modes_used.size());
- size_t j = 0;
- for (int mode : src->sensor_pixel_modes_used) {
- dst3_7.sensorPixelModesUsed[j++] =
- static_cast<CameraMetadataEnumAndroidSensorPixelMode>(mode);
- }
- activeStreams.insert(streamId);
- // Create Buffer ID map if necessary
- mBufferRecords.tryCreateBufferCache(streamId);
- }
- // remove BufferIdMap for deleted streams
- mBufferRecords.removeInactiveBufferCaches(activeStreams);
-
- StreamConfigurationMode operationMode;
- res = mapToStreamConfigurationMode(
- (camera_stream_configuration_mode_t)config->operation_mode,
- /*out*/ &operationMode);
- if (res != OK) {
- return res;
- }
- requestedConfiguration3_7.operationMode = operationMode;
- size_t sessionParamSize = get_camera_metadata_size(sessionParams);
- requestedConfiguration3_7.operationMode = operationMode;
- requestedConfiguration3_7.sessionParams.setToExternal(
- reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(sessionParams)),
- sessionParamSize);
-
- // See which version of HAL we have
- if (mHidlSession_3_7 != nullptr) {
- requestedConfiguration3_7.streamConfigCounter = mNextStreamConfigCounter++;
- requestedConfiguration3_7.multiResolutionInputImage =
- config->input_is_multi_resolution;
-
- const camera_metadata_t* rawMetadata = cameraCharacteristics.getAndLock();
- ::android::hardware::camera::device::V3_2::CameraMetadata hidlChars = {};
- hidlChars.setToExternal(
- reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(rawMetadata)),
- get_camera_metadata_size(rawMetadata));
- cameraCharacteristics.unlock(rawMetadata);
-
- sp<hardware::camera::device::V3_7::ICameraInjectionSession>
- hidlInjectionSession_3_7;
- auto castInjectionResult_3_7 =
- device::V3_7::ICameraInjectionSession::castFrom(mHidlSession_3_7);
- if (castInjectionResult_3_7.isOk()) {
- hidlInjectionSession_3_7 = castInjectionResult_3_7;
- } else {
- ALOGE("%s: Transaction error: %s", __FUNCTION__,
- castInjectionResult_3_7.description().c_str());
- return DEAD_OBJECT;
- }
-
- auto err = hidlInjectionSession_3_7->configureInjectionStreams(
- requestedConfiguration3_7, hidlChars);
- if (!err.isOk()) {
- ALOGE("%s: Transaction error: %s", __FUNCTION__,
- err.description().c_str());
- return DEAD_OBJECT;
- }
- } else {
- ALOGE("%s: mHidlSession_3_7 does not exist, the lowest version of injection "
- "session is 3.7", __FUNCTION__);
- return DEAD_OBJECT;
- }
-
- return res;
-}
-
-status_t Camera3Device::HalInterface::wrapAsHidlRequest(camera_capture_request_t* request,
- /*out*/device::V3_2::CaptureRequest* captureRequest,
- /*out*/std::vector<native_handle_t*>* handlesCreated,
- /*out*/std::vector<std::pair<int32_t, int32_t>>* inflightBuffers) {
- ATRACE_CALL();
- if (captureRequest == nullptr || handlesCreated == nullptr || inflightBuffers == nullptr) {
- ALOGE("%s: captureRequest (%p), handlesCreated (%p), and inflightBuffers(%p) "
- "must not be null", __FUNCTION__, captureRequest, handlesCreated, inflightBuffers);
- return BAD_VALUE;
- }
-
- captureRequest->frameNumber = request->frame_number;
-
- captureRequest->fmqSettingsSize = 0;
-
- {
- if (request->input_buffer != nullptr) {
- int32_t streamId = Camera3Stream::cast(request->input_buffer->stream)->getId();
- buffer_handle_t buf = *(request->input_buffer->buffer);
- auto pair = getBufferId(buf, streamId);
- bool isNewBuffer = pair.first;
- uint64_t bufferId = pair.second;
- captureRequest->inputBuffer.streamId = streamId;
- captureRequest->inputBuffer.bufferId = bufferId;
- captureRequest->inputBuffer.buffer = (isNewBuffer) ? buf : nullptr;
- captureRequest->inputBuffer.status = BufferStatus::OK;
- native_handle_t *acquireFence = nullptr;
- if (request->input_buffer->acquire_fence != -1) {
- acquireFence = native_handle_create(1,0);
- acquireFence->data[0] = request->input_buffer->acquire_fence;
- handlesCreated->push_back(acquireFence);
- }
- captureRequest->inputBuffer.acquireFence = acquireFence;
- captureRequest->inputBuffer.releaseFence = nullptr;
-
- mBufferRecords.pushInflightBuffer(captureRequest->frameNumber, streamId,
- request->input_buffer->buffer);
- inflightBuffers->push_back(std::make_pair(captureRequest->frameNumber, streamId));
- } else {
- captureRequest->inputBuffer.streamId = -1;
- captureRequest->inputBuffer.bufferId = BUFFER_ID_NO_BUFFER;
- }
-
- captureRequest->outputBuffers.resize(request->num_output_buffers);
- for (size_t i = 0; i < request->num_output_buffers; i++) {
- const camera_stream_buffer_t *src = request->output_buffers + i;
- StreamBuffer &dst = captureRequest->outputBuffers[i];
- int32_t streamId = Camera3Stream::cast(src->stream)->getId();
- if (src->buffer != nullptr) {
- buffer_handle_t buf = *(src->buffer);
- auto pair = getBufferId(buf, streamId);
- bool isNewBuffer = pair.first;
- dst.bufferId = pair.second;
- dst.buffer = isNewBuffer ? buf : nullptr;
- native_handle_t *acquireFence = nullptr;
- if (src->acquire_fence != -1) {
- acquireFence = native_handle_create(1,0);
- acquireFence->data[0] = src->acquire_fence;
- handlesCreated->push_back(acquireFence);
- }
- dst.acquireFence = acquireFence;
- } else if (mUseHalBufManager) {
- // HAL buffer management path
- dst.bufferId = BUFFER_ID_NO_BUFFER;
- dst.buffer = nullptr;
- dst.acquireFence = nullptr;
- } else {
- ALOGE("%s: cannot send a null buffer in capture request!", __FUNCTION__);
- return BAD_VALUE;
- }
- dst.streamId = streamId;
- dst.status = BufferStatus::OK;
- dst.releaseFence = nullptr;
-
- // Output buffers are empty when using HAL buffer manager
- if (!mUseHalBufManager) {
- mBufferRecords.pushInflightBuffer(
- captureRequest->frameNumber, streamId, src->buffer);
- inflightBuffers->push_back(std::make_pair(captureRequest->frameNumber, streamId));
- }
- }
- }
- return OK;
-}
-
void Camera3Device::HalInterface::cleanupNativeHandles(
std::vector<native_handle_t*> *handles, bool closeFd) {
if (handles == nullptr) {
@@ -3843,302 +2746,6 @@
return;
}
-status_t Camera3Device::HalInterface::processBatchCaptureRequests(
- std::vector<camera_capture_request_t*>& requests,/*out*/uint32_t* numRequestProcessed) {
- ATRACE_NAME("CameraHal::processBatchCaptureRequests");
- 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;
- }
-
- 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_7 != nullptr) {
- captureRequests_3_7.resize(batchSize);
- } else if (hidlSession_3_4 != nullptr) {
- captureRequests_3_4.resize(batchSize);
- } else {
- captureRequests.resize(batchSize);
- }
- std::vector<native_handle_t*> handlesCreated;
- std::vector<std::pair<int32_t, int32_t>> inflightBuffers;
-
- status_t res = OK;
- for (size_t i = 0; i < batchSize; i++) {
- 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 {
- res = wrapAsHidlRequest(requests[i], /*out*/&captureRequests[i],
- /*out*/&handlesCreated, /*out*/&inflightBuffers);
- }
- if (res != OK) {
- mBufferRecords.popInflightBuffers(inflightBuffers);
- cleanupNativeHandles(&handlesCreated);
- return res;
- }
- }
-
- std::vector<device::V3_2::BufferCache> cachesToRemove;
- {
- std::lock_guard<std::mutex> lock(mFreedBuffersLock);
- for (auto& pair : mFreedBuffers) {
- // The stream might have been removed since onBufferFreed
- if (mBufferRecords.isStreamCached(pair.first)) {
- cachesToRemove.push_back({pair.first, pair.second});
- }
- }
- mFreedBuffers.clear();
- }
-
- common::V1_0::Status status = common::V1_0::Status::INTERNAL_ERROR;
- *numRequestProcessed = 0;
-
- // Write metadata to FMQ.
- for (size_t i = 0; i < batchSize; i++) {
- camera_capture_request_t* request = requests[i];
- device::V3_2::CaptureRequest* captureRequest;
- 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];
- }
-
- if (request->settings != nullptr) {
- size_t settingsSize = get_camera_metadata_size(request->settings);
- if (mRequestMetadataQueue != nullptr && mRequestMetadataQueue->write(
- reinterpret_cast<const uint8_t*>(request->settings), settingsSize)) {
- captureRequest->settings.resize(0);
- captureRequest->fmqSettingsSize = settingsSize;
- } else {
- if (mRequestMetadataQueue != nullptr) {
- ALOGW("%s: couldn't utilize fmq, fallback to hwbinder", __FUNCTION__);
- }
- captureRequest->settings.setToExternal(
- reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(request->settings)),
- get_camera_metadata_size(request->settings));
- captureRequest->fmqSettingsSize = 0u;
- }
- } else {
- // A null request settings maps to a size-0 CameraMetadata
- captureRequest->settings.resize(0);
- captureRequest->fmqSettingsSize = 0u;
- }
-
- // 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)) {
- physicalCameraSettings[j].settings.resize(0);
- physicalCameraSettings[j].fmqSettingsSize = settingsSize;
- } else {
- if (mRequestMetadataQueue != nullptr) {
- ALOGW("%s: couldn't utilize fmq, fallback to hwbinder", __FUNCTION__);
- }
- 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]));
- physicalCameraSettings[j].fmqSettingsSize = 0u;
- }
- } else {
- physicalCameraSettings[j].fmqSettingsSize = 0u;
- physicalCameraSettings[j].settings.resize(0);
- }
- physicalCameraSettings[j].physicalCameraId = request->physcam_id[j];
- }
- }
- }
-
- hardware::details::return_status err;
- auto resultCallback =
- [&status, &numRequestProcessed] (auto s, uint32_t n) {
- status = s;
- *numRequestProcessed = n;
- };
- 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 {
- err = mHidlSession->processCaptureRequest(captureRequests, cachesToRemove,
- resultCallback);
- }
- if (!err.isOk()) {
- ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
- status = common::V1_0::Status::CAMERA_DISCONNECTED;
- }
-
- if (status == common::V1_0::Status::OK && *numRequestProcessed != batchSize) {
- ALOGE("%s: processCaptureRequest returns OK but processed %d/%zu requests",
- __FUNCTION__, *numRequestProcessed, batchSize);
- status = common::V1_0::Status::INTERNAL_ERROR;
- }
-
- res = CameraProviderManager::mapToStatusT(status);
- if (res == OK) {
- if (mHidlSession->isRemote()) {
- // Only close acquire fence FDs when the HIDL transaction succeeds (so the FDs have been
- // sent to camera HAL processes)
- cleanupNativeHandles(&handlesCreated, /*closeFd*/true);
- } else {
- // In passthrough mode the FDs are now owned by HAL
- cleanupNativeHandles(&handlesCreated);
- }
- } else {
- mBufferRecords.popInflightBuffers(inflightBuffers);
- cleanupNativeHandles(&handlesCreated);
- }
- return res;
-}
-
-status_t Camera3Device::HalInterface::flush() {
- ATRACE_NAME("CameraHal::flush");
- if (!valid()) return INVALID_OPERATION;
- status_t res = OK;
-
- auto err = mHidlSession->flush();
- if (!err.isOk()) {
- ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
- res = DEAD_OBJECT;
- } else {
- res = CameraProviderManager::mapToStatusT(err);
- }
-
- return res;
-}
-
-status_t Camera3Device::HalInterface::dump(int /*fd*/) {
- ATRACE_NAME("CameraHal::dump");
- if (!valid()) return INVALID_OPERATION;
-
- // Handled by CameraProviderManager::dump
-
- return OK;
-}
-
-status_t Camera3Device::HalInterface::close() {
- ATRACE_NAME("CameraHal::close()");
- if (!valid()) return INVALID_OPERATION;
- status_t res = OK;
-
- auto err = mHidlSession->close();
- // Interface will be dead shortly anyway, so don't log errors
- if (!err.isOk()) {
- res = DEAD_OBJECT;
- }
-
- return res;
-}
-
-void Camera3Device::HalInterface::signalPipelineDrain(const std::vector<int>& streamIds) {
- ATRACE_NAME("CameraHal::signalPipelineDrain");
- if (!valid() || mHidlSession_3_5 == nullptr) {
- ALOGE("%s called on invalid camera!", __FUNCTION__);
- return;
- }
-
- auto err = mHidlSession_3_5->signalStreamFlush(streamIds, mNextStreamConfigCounter - 1);
- if (!err.isOk()) {
- ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
- return;
- }
-}
-
-status_t Camera3Device::HalInterface::switchToOffline(
- const std::vector<int32_t>& streamsToKeep,
- /*out*/hardware::camera::device::V3_6::CameraOfflineSessionInfo* offlineSessionInfo,
- /*out*/sp<hardware::camera::device::V3_6::ICameraOfflineSession>* offlineSession,
- /*out*/camera3::BufferRecords* bufferRecords) {
- ATRACE_NAME("CameraHal::switchToOffline");
- if (!valid() || mHidlSession_3_6 == nullptr) {
- ALOGE("%s called on invalid camera!", __FUNCTION__);
- return INVALID_OPERATION;
- }
-
- if (offlineSessionInfo == nullptr || offlineSession == nullptr || bufferRecords == nullptr) {
- ALOGE("%s: output arguments must not be null!", __FUNCTION__);
- return INVALID_OPERATION;
- }
-
- common::V1_0::Status status = common::V1_0::Status::INTERNAL_ERROR;
- auto resultCallback =
- [&status, &offlineSessionInfo, &offlineSession] (auto s, auto info, auto session) {
- status = s;
- *offlineSessionInfo = info;
- *offlineSession = session;
- };
- auto err = mHidlSession_3_6->switchToOffline(streamsToKeep, resultCallback);
-
- if (!err.isOk()) {
- ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
- return DEAD_OBJECT;
- }
-
- status_t ret = CameraProviderManager::mapToStatusT(status);
- if (ret != OK) {
- return ret;
- }
-
- // TODO: assert no ongoing requestBuffer/returnBuffer call here
- // TODO: update RequestBufferStateMachine to block requestBuffer/returnBuffer once HAL
- // returns from switchToOffline.
-
-
- // Validate buffer caches
- std::vector<int32_t> streams;
- streams.reserve(offlineSessionInfo->offlineStreams.size());
- for (auto offlineStream : offlineSessionInfo->offlineStreams) {
- int32_t id = offlineStream.id;
- streams.push_back(id);
- // Verify buffer caches
- std::vector<uint64_t> bufIds(offlineStream.circulatingBufferIds.begin(),
- offlineStream.circulatingBufferIds.end());
- if (!verifyBufferIds(id, bufIds)) {
- ALOGE("%s: stream ID %d buffer cache records mismatch!", __FUNCTION__, id);
- return UNKNOWN_ERROR;
- }
- }
-
- // Move buffer records
- bufferRecords->takeBufferCaches(mBufferRecords, streams);
- bufferRecords->takeInflightBufferMap(mBufferRecords);
- bufferRecords->takeRequestedBufferMap(mBufferRecords);
- return ret;
-}
-
void Camera3Device::HalInterface::getInflightBufferKeys(
std::vector<std::pair<int32_t, int32_t>>* out) {
mBufferRecords.getInflightBufferKeys(out);
@@ -4383,10 +2990,20 @@
}
status_t Camera3Device::RequestThread::clearRepeatingRequestsLocked(/*out*/int64_t *lastFrameNumber) {
+ std::vector<int32_t> streamIds;
+ for (const auto& request : mRepeatingRequests) {
+ for (const auto& stream : request->mOutputStreams) {
+ streamIds.push_back(stream->getId());
+ }
+ }
+
mRepeatingRequests.clear();
if (lastFrameNumber != NULL) {
*lastFrameNumber = mRepeatingLastFrameNumber;
}
+
+ mInterface->repeatingRequestEnd(mRepeatingLastFrameNumber, streamIds);
+
mRepeatingLastFrameNumber = hardware::camera2::ICameraDeviceUser::NO_IN_FLIGHT_REPEATING_FRAMES;
return OK;
}
@@ -5351,38 +3968,6 @@
mPrevRequest.clear();
}
-status_t Camera3Device::RequestThread::switchToOffline(
- const std::vector<int32_t>& streamsToKeep,
- /*out*/hardware::camera::device::V3_6::CameraOfflineSessionInfo* offlineSessionInfo,
- /*out*/sp<hardware::camera::device::V3_6::ICameraOfflineSession>* offlineSession,
- /*out*/camera3::BufferRecords* bufferRecords) {
- Mutex::Autolock l(mRequestLock);
- clearRepeatingRequestsLocked(/*lastFrameNumber*/nullptr);
-
- // Wait until request thread is fully stopped
- // TBD: check if request thread is being paused by other APIs (shouldn't be)
-
- // We could also check for mRepeatingRequests.empty(), but the API interface
- // is serialized by Camera3Device::mInterfaceLock so no one should be able to submit any
- // new requests during the call; hence skip that check.
- bool queueEmpty = mNextRequests.empty() && mRequestQueue.empty();
- while (!queueEmpty) {
- status_t res = mRequestSubmittedSignal.waitRelative(mRequestLock, kRequestSubmitTimeout);
- if (res == TIMED_OUT) {
- ALOGE("%s: request thread failed to submit one request within timeout!", __FUNCTION__);
- return res;
- } else if (res != OK) {
- ALOGE("%s: request thread failed to submit a request: %s (%d)!",
- __FUNCTION__, strerror(-res), res);
- return res;
- }
- queueEmpty = mNextRequests.empty() && mRequestQueue.empty();
- }
-
- return mInterface->switchToOffline(
- streamsToKeep, offlineSessionInfo, offlineSession, bufferRecords);
-}
-
status_t Camera3Device::RequestThread::setRotateAndCropAutoBehavior(
camera_metadata_enum_android_scaler_rotate_and_crop_t rotateAndCropValue) {
ATRACE_CALL();
@@ -6413,220 +4998,6 @@
return ret;
}
-status_t Camera3Device::switchToOffline(
- const std::vector<int32_t>& streamsToKeep,
- /*out*/ sp<CameraOfflineSessionBase>* session) {
- ATRACE_CALL();
- if (session == nullptr) {
- ALOGE("%s: session must not be null", __FUNCTION__);
- return BAD_VALUE;
- }
-
- Mutex::Autolock il(mInterfaceLock);
-
- bool hasInputStream = mInputStream != nullptr;
- int32_t inputStreamId = hasInputStream ? mInputStream->getId() : -1;
- bool inputStreamSupportsOffline = hasInputStream ?
- mInputStream->getOfflineProcessingSupport() : false;
- auto outputStreamIds = mOutputStreams.getStreamIds();
- auto streamIds = outputStreamIds;
- if (hasInputStream) {
- streamIds.push_back(mInputStream->getId());
- }
-
- // Check all streams in streamsToKeep supports offline mode
- for (auto id : streamsToKeep) {
- if (std::find(streamIds.begin(), streamIds.end(), id) == streamIds.end()) {
- ALOGE("%s: Unknown stream ID %d", __FUNCTION__, id);
- return BAD_VALUE;
- } else if (id == inputStreamId) {
- if (!inputStreamSupportsOffline) {
- ALOGE("%s: input stream %d cannot be switched to offline",
- __FUNCTION__, id);
- return BAD_VALUE;
- }
- } else {
- sp<camera3::Camera3OutputStreamInterface> stream = mOutputStreams.get(id);
- if (!stream->getOfflineProcessingSupport()) {
- ALOGE("%s: output stream %d cannot be switched to offline",
- __FUNCTION__, id);
- return BAD_VALUE;
- }
- }
- }
-
- // TODO: block surface sharing and surface group streams until we can support them
-
- // Stop repeating request, wait until all remaining requests are submitted, then call into
- // HAL switchToOffline
- hardware::camera::device::V3_6::CameraOfflineSessionInfo offlineSessionInfo;
- sp<hardware::camera::device::V3_6::ICameraOfflineSession> offlineSession;
- camera3::BufferRecords bufferRecords;
- status_t ret = mRequestThread->switchToOffline(
- streamsToKeep, &offlineSessionInfo, &offlineSession, &bufferRecords);
-
- if (ret != OK) {
- SET_ERR("Switch to offline failed: %s (%d)", strerror(-ret), ret);
- return ret;
- }
-
- bool succ = mRequestBufferSM.onSwitchToOfflineSuccess();
- if (!succ) {
- SET_ERR("HAL must not be calling requestStreamBuffers call");
- // TODO: block ALL callbacks from HAL till app configured new streams?
- return UNKNOWN_ERROR;
- }
-
- // Verify offlineSessionInfo
- std::vector<int32_t> offlineStreamIds;
- offlineStreamIds.reserve(offlineSessionInfo.offlineStreams.size());
- for (auto offlineStream : offlineSessionInfo.offlineStreams) {
- // verify stream IDs
- int32_t id = offlineStream.id;
- if (std::find(streamIds.begin(), streamIds.end(), id) == streamIds.end()) {
- SET_ERR("stream ID %d not found!", id);
- return UNKNOWN_ERROR;
- }
-
- // When not using HAL buf manager, only allow streams requested by app to be preserved
- if (!mUseHalBufManager) {
- if (std::find(streamsToKeep.begin(), streamsToKeep.end(), id) == streamsToKeep.end()) {
- SET_ERR("stream ID %d must not be switched to offline!", id);
- return UNKNOWN_ERROR;
- }
- }
-
- offlineStreamIds.push_back(id);
- sp<Camera3StreamInterface> stream = (id == inputStreamId) ?
- static_cast<sp<Camera3StreamInterface>>(mInputStream) :
- static_cast<sp<Camera3StreamInterface>>(mOutputStreams.get(id));
- // Verify number of outstanding buffers
- if (stream->getOutstandingBuffersCount() != offlineStream.numOutstandingBuffers) {
- SET_ERR("Offline stream %d # of remaining buffer mismatch: (%zu,%d) (service/HAL)",
- id, stream->getOutstandingBuffersCount(), offlineStream.numOutstandingBuffers);
- return UNKNOWN_ERROR;
- }
- }
-
- // Verify all streams to be deleted don't have any outstanding buffers
- if (hasInputStream && std::find(offlineStreamIds.begin(), offlineStreamIds.end(),
- inputStreamId) == offlineStreamIds.end()) {
- if (mInputStream->hasOutstandingBuffers()) {
- SET_ERR("Input stream %d still has %zu outstanding buffer!",
- inputStreamId, mInputStream->getOutstandingBuffersCount());
- return UNKNOWN_ERROR;
- }
- }
-
- for (const auto& outStreamId : outputStreamIds) {
- if (std::find(offlineStreamIds.begin(), offlineStreamIds.end(),
- outStreamId) == offlineStreamIds.end()) {
- auto outStream = mOutputStreams.get(outStreamId);
- if (outStream->hasOutstandingBuffers()) {
- SET_ERR("Output stream %d still has %zu outstanding buffer!",
- outStreamId, outStream->getOutstandingBuffersCount());
- return UNKNOWN_ERROR;
- }
- }
- }
-
- InFlightRequestMap offlineReqs;
- // Verify inflight requests and their pending buffers
- {
- std::lock_guard<std::mutex> l(mInFlightLock);
- for (auto offlineReq : offlineSessionInfo.offlineRequests) {
- int idx = mInFlightMap.indexOfKey(offlineReq.frameNumber);
- if (idx == NAME_NOT_FOUND) {
- SET_ERR("Offline request frame number %d not found!", offlineReq.frameNumber);
- return UNKNOWN_ERROR;
- }
-
- const auto& inflightReq = mInFlightMap.valueAt(idx);
- // TODO: check specific stream IDs
- size_t numBuffersLeft = static_cast<size_t>(inflightReq.numBuffersLeft);
- if (numBuffersLeft != offlineReq.pendingStreams.size()) {
- SET_ERR("Offline request # of remaining buffer mismatch: (%d,%d) (service/HAL)",
- inflightReq.numBuffersLeft, offlineReq.pendingStreams.size());
- return UNKNOWN_ERROR;
- }
- offlineReqs.add(offlineReq.frameNumber, inflightReq);
- }
- }
-
- // Create Camera3OfflineSession and transfer object ownership
- // (streams, inflight requests, buffer caches)
- camera3::StreamSet offlineStreamSet;
- sp<camera3::Camera3Stream> inputStream;
- for (auto offlineStream : offlineSessionInfo.offlineStreams) {
- int32_t id = offlineStream.id;
- if (mInputStream != nullptr && id == mInputStream->getId()) {
- inputStream = mInputStream;
- } else {
- offlineStreamSet.add(id, mOutputStreams.get(id));
- }
- }
-
- // TODO: check if we need to lock before copying states
- // though technically no other thread should be talking to Camera3Device at this point
- Camera3OfflineStates offlineStates(
- mTagMonitor, mVendorTagId, mUseHalBufManager, mNeedFixupMonochromeTags,
- mUsePartialResult, mNumPartialResults, mLastCompletedRegularFrameNumber,
- mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
- mNextResultFrameNumber, mNextReprocessResultFrameNumber,
- mNextZslStillResultFrameNumber, mNextShutterFrameNumber,
- mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
- mDeviceInfo, mPhysicalDeviceInfoMap, mDistortionMappers,
- mZoomRatioMappers, mRotateAndCropMappers);
-
- *session = new Camera3OfflineSession(mId, inputStream, offlineStreamSet,
- std::move(bufferRecords), offlineReqs, offlineStates, offlineSession);
-
- // Delete all streams that has been transferred to offline session
- Mutex::Autolock l(mLock);
- for (auto offlineStream : offlineSessionInfo.offlineStreams) {
- int32_t id = offlineStream.id;
- if (mInputStream != nullptr && id == mInputStream->getId()) {
- mInputStream.clear();
- } else {
- mOutputStreams.remove(id);
- }
- }
-
- // disconnect all other streams and switch to UNCONFIGURED state
- if (mInputStream != nullptr) {
- ret = mInputStream->disconnect();
- if (ret != OK) {
- SET_ERR_L("disconnect input stream failed!");
- return UNKNOWN_ERROR;
- }
- }
-
- for (auto streamId : mOutputStreams.getStreamIds()) {
- sp<Camera3StreamInterface> stream = mOutputStreams.get(streamId);
- ret = stream->disconnect();
- if (ret != OK) {
- SET_ERR_L("disconnect output stream %d failed!", streamId);
- return UNKNOWN_ERROR;
- }
- }
-
- mInputStream.clear();
- mOutputStreams.clear();
- mNeedConfig = true;
- internalUpdateStatusLocked(STATUS_UNCONFIGURED);
- mOperatingMode = NO_MODE;
- mIsConstrainedHighSpeedConfiguration = false;
- mRequestThread->clearPreviousRequest();
-
- return OK;
- // TO be done by CameraDeviceClient/Camera3OfflineSession
- // register the offline client to camera service
- // Setup result passthing threads etc
- // Initialize offline session so HAL can start sending callback to it (result Fmq)
- // TODO: check how many onIdle callback will be sent
- // Java side to make sure the CameraCaptureSession is properly closed
-}
-
void Camera3Device::getOfflineStreamIds(std::vector<int> *offlineStreamIds) {
ATRACE_CALL();
@@ -6713,7 +5084,7 @@
}
}
- res = mInjectionMethods->injectionInitialize(injectedCamId, manager, this);
+ res = injectionCameraInitialize(injectedCamId, manager);
if (res != OK) {
ALOGE("%s: Failed to initialize the injection camera! ret != NO_ERROR: %d",
__FUNCTION__, res);
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index d08c41f..6c4ba49 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -29,21 +29,9 @@
#include <utils/KeyedVector.h>
#include <utils/Timers.h>
-#include <android/hardware/camera/device/3.2/ICameraDevice.h>
-#include <android/hardware/camera/device/3.2/ICameraDeviceSession.h>
-#include <android/hardware/camera/device/3.3/ICameraDeviceSession.h>
-#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>
-#include <android/hardware/camera/device/3.8/ICameraDeviceCallback.h>
-#include <fmq/MessageQueue.h>
-
#include <camera/CaptureResult.h>
+#include "android/hardware/camera/metadata/3.8/types.h"
#include "common/CameraDeviceBase.h"
#include "device3/BufferUtils.h"
#include "device3/StatusTracker.h"
@@ -57,6 +45,7 @@
#include "device3/Camera3OfflineSession.h"
#include "device3/Camera3StreamInterface.h"
#include "utils/TagMonitor.h"
+#include "utils/IPCTransport.h"
#include "utils/LatencyHistogram.h"
#include <camera_metadata_hidden.h>
@@ -84,11 +73,11 @@
*/
class Camera3Device :
public CameraDeviceBase,
- virtual public hardware::camera::device::V3_8::ICameraDeviceCallback,
public camera3::SetErrorInterface,
public camera3::InflightRequestUpdateInterface,
public camera3::RequestBufferInterface,
public camera3::FlushBufferInterface {
+ friend class HidlCamera3Device;
public:
explicit Camera3Device(const String8& id, bool overrideForPerfClass, bool legacyClient = false);
@@ -104,7 +93,9 @@
metadata_vendor_id_t getVendorTagId() const override { return mVendorTagId; }
// Transitions to idle state on success.
- status_t initialize(sp<CameraProviderManager> manager, const String8& monitorTags) override;
+ virtual status_t initialize(sp<CameraProviderManager> /*manager*/,
+ const String8& /*monitorTags*/) = 0;
+
status_t disconnect() override;
status_t dump(int fd, const Vector<String16> &args) override;
status_t startWatchingTags(const String8 &tags) override;
@@ -141,7 +132,9 @@
std::vector<int> *surfaceIds = nullptr,
int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID,
bool isShared = false, bool isMultiResolution = false,
- uint64_t consumerUsage = 0) override;
+ uint64_t consumerUsage = 0,
+ int dynamicRangeProfile =
+ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD) override;
status_t createStream(const std::vector<sp<Surface>>& consumers,
bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
@@ -151,7 +144,9 @@
std::vector<int> *surfaceIds = nullptr,
int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID,
bool isShared = false, bool isMultiResolution = false,
- uint64_t consumerUsage = 0) override;
+ uint64_t consumerUsage = 0,
+ int dynamicRangeProfile =
+ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD) override;
status_t createInputStream(
uint32_t width, uint32_t height, int format, bool isMultiResolution,
@@ -196,9 +191,11 @@
status_t prepare(int maxCount, int streamId) override;
- ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const override;
- ssize_t getPointCloudBufferSize() const;
- ssize_t getRawOpaqueBufferSize(int32_t width, int32_t height, bool maxResolution) const;
+ ssize_t getJpegBufferSize(const CameraMetadata &info, uint32_t width,
+ uint32_t height) const override;
+ ssize_t getPointCloudBufferSize(const CameraMetadata &info) const;
+ ssize_t getRawOpaqueBufferSize(const CameraMetadata &info, int32_t width, int32_t height,
+ bool maxResolution) const;
// Methods called by subclasses
void notifyStatus(bool idle); // updates from StatusTracker
@@ -227,8 +224,10 @@
nsecs_t getExpectedInFlightDuration() override;
- status_t switchToOffline(const std::vector<int32_t>& streamsToKeep,
- /*out*/ sp<CameraOfflineSessionBase>* session) override;
+ virtual status_t switchToOffline(const std::vector<int32_t>& ,
+ /*out*/ sp<CameraOfflineSessionBase>* ) override {
+ return INVALID_OPERATION;
+ };
// RequestBufferInterface
bool startRequestBuffer() override;
@@ -279,33 +278,10 @@
*/
status_t stopInjection();
- /**
- * Helper functions to map between framework and HIDL values
- */
- static hardware::graphics::common::V1_0::PixelFormat mapToPixelFormat(int frameworkFormat);
- static hardware::camera::device::V3_2::DataspaceFlags mapToHidlDataspace(
- android_dataspace dataSpace);
- static hardware::camera::device::V3_2::BufferUsageFlags mapToConsumerUsage(uint64_t usage);
- static hardware::camera::device::V3_2::StreamRotation mapToStreamRotation(
- camera_stream_rotation_t rotation);
- // Returns a negative error code if the passed-in operation mode is not valid.
- static status_t mapToStreamConfigurationMode(camera_stream_configuration_mode_t operationMode,
- /*out*/ hardware::camera::device::V3_2::StreamConfigurationMode *mode);
- static int mapToFrameworkFormat(hardware::graphics::common::V1_0::PixelFormat pixelFormat);
- static android_dataspace mapToFrameworkDataspace(
- hardware::camera::device::V3_2::DataspaceFlags);
- static uint64_t mapConsumerToFrameworkUsage(
- hardware::camera::device::V3_2::BufferUsageFlags usage);
- static uint64_t mapProducerToFrameworkUsage(
- hardware::camera::device::V3_2::BufferUsageFlags usage);
-
- private:
+ protected:
status_t disconnectImpl();
static status_t removeFwkOnlyRegionKeys(CameraMetadata *request);
- // internal typedefs
- using RequestMetadataQueue = hardware::MessageQueue<uint8_t, hardware::kSynchronizedReadWrite>;
-
static const size_t kDumpLockAttempts = 10;
static const size_t kDumpSleepDuration = 100000; // 0.10 sec
static const nsecs_t kActiveTimeout = 500000000; // 500 ms
@@ -351,68 +327,65 @@
// Flag indicating is the current active stream configuration is constrained high speed.
bool mIsConstrainedHighSpeedConfiguration;
- // FMQ to write result on. Must be guarded by mProcessCaptureResultLock.
- std::unique_ptr<ResultMetadataQueue> mResultMetadataQueue;
-
/**** Scope for mLock ****/
- /**
- * Adapter for legacy HAL / HIDL HAL interface calls; calls either into legacy HALv3 or the
- * HIDL HALv3 interfaces.
- */
class HalInterface : public camera3::Camera3StreamBufferFreedListener,
public camera3::BufferRecordsInterface {
public:
- HalInterface(sp<hardware::camera::device::V3_2::ICameraDeviceSession> &session,
- std::shared_ptr<RequestMetadataQueue> queue,
- bool useHalBufManager, bool supportOfflineProcessing);
+ HalInterface(bool useHalBufManager, bool supportOfflineProcessing) :
+ mUseHalBufManager(useHalBufManager),
+ mIsReconfigurationQuerySupported(true),
+ mSupportOfflineProcessing(supportOfflineProcessing)
+ {};
HalInterface(const HalInterface &other);
HalInterface();
+ virtual IPCTransport getTransportType() = 0;
+
// Returns true if constructed with a valid device or session, and not yet cleared
- bool valid();
+ virtual bool valid() = 0;
// Reset this HalInterface object (does not call close())
- void clear();
+ virtual void clear() = 0;
// Calls into the HAL interface
// Caller takes ownership of requestTemplate
- status_t constructDefaultRequestSettings(camera_request_template templateId,
- /*out*/ camera_metadata_t **requestTemplate);
- status_t configureStreams(const camera_metadata_t *sessionParams,
- /*inout*/ camera_stream_configuration_t *config,
- const std::vector<uint32_t>& bufferSizes);
+ virtual status_t constructDefaultRequestSettings(camera_request_template templateId,
+ /*out*/ camera_metadata_t **requestTemplate) = 0;
+
+ virtual status_t configureStreams(const camera_metadata_t * sessionParams,
+ /*inout*/ camera_stream_configuration_t * config,
+ const std::vector<uint32_t>& bufferSizes) = 0;
// The injection camera configures the streams to hal.
- status_t configureInjectedStreams(
+ virtual status_t configureInjectedStreams(
const camera_metadata_t* sessionParams,
/*inout*/ camera_stream_configuration_t* config,
const std::vector<uint32_t>& bufferSizes,
- const CameraMetadata& cameraCharacteristics);
+ const CameraMetadata& cameraCharacteristics) = 0;
// When the call succeeds, the ownership of acquire fences in requests is transferred to
// HalInterface. More specifically, the current implementation will send the fence to
// HAL process and close the FD in cameraserver process. When the call fails, the ownership
// of the acquire fence still belongs to the caller.
- status_t processBatchCaptureRequests(
+ virtual status_t processBatchCaptureRequests(
std::vector<camera_capture_request_t*>& requests,
- /*out*/uint32_t* numRequestProcessed);
- status_t flush();
- status_t dump(int fd);
- status_t close();
+ /*out*/uint32_t* numRequestProcessed) = 0;
- void signalPipelineDrain(const std::vector<int>& streamIds);
- bool isReconfigurationRequired(CameraMetadata& oldSessionParams,
- CameraMetadata& newSessionParams);
+ virtual status_t flush() = 0;
- // Upon successful return, HalInterface will return buffer maps needed for offline
- // processing, and clear all its internal buffer maps.
- status_t switchToOffline(
- const std::vector<int32_t>& streamsToKeep,
- /*out*/hardware::camera::device::V3_6::CameraOfflineSessionInfo* offlineSessionInfo,
- /*out*/sp<hardware::camera::device::V3_6::ICameraOfflineSession>* offlineSession,
- /*out*/camera3::BufferRecords* bufferRecords);
+ virtual status_t dump(int fd) = 0;
+
+ virtual status_t close() = 0;
+
+ virtual void signalPipelineDrain(const std::vector<int>& streamIds) = 0;
+
+ virtual bool isReconfigurationRequired(CameraMetadata& oldSessionParams,
+ CameraMetadata& newSessionParams) = 0;
+
+ virtual status_t repeatingRequestEnd(uint32_t frameNumber,
+ const std::vector<int32_t> &streamIds) = 0;
/////////////////////////////////////////////////////////////////////
// Implements BufferRecordsInterface
@@ -443,38 +416,36 @@
void onStreamReConfigured(int streamId);
- private:
- // Always valid
- sp<hardware::camera::device::V3_2::ICameraDeviceSession> mHidlSession;
- // Valid if ICameraDeviceSession is @3.3 or newer
- sp<hardware::camera::device::V3_3::ICameraDeviceSession> mHidlSession_3_3;
- // Valid if ICameraDeviceSession is @3.4 or newer
- sp<hardware::camera::device::V3_4::ICameraDeviceSession> mHidlSession_3_4;
- // Valid if ICameraDeviceSession is @3.5 or newer
- 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;
-
- // The output HIDL request still depends on input camera_capture_request_t
- // Do not free input camera_capture_request_t before output HIDL request
- status_t wrapAsHidlRequest(camera_capture_request_t* in,
- /*out*/hardware::camera::device::V3_2::CaptureRequest* out,
- /*out*/std::vector<native_handle_t*>* handlesCreated,
- /*out*/std::vector<std::pair<int32_t, int32_t>>* inflightBuffers);
-
- status_t pushInflightBufferLocked(int32_t frameNumber, int32_t streamId,
- buffer_handle_t *buffer);
-
- // Pop inflight buffers based on pairs of (frameNumber,streamId)
- void popInflightBuffers(const std::vector<std::pair<int32_t, int32_t>>& buffers);
+ protected:
// Return true if the input caches match what we have; otherwise false
bool verifyBufferIds(int32_t streamId, std::vector<uint64_t>& inBufIds);
+ template <typename OfflineSessionInfoT>
+ status_t verifyBufferCaches(
+ const OfflineSessionInfoT *offlineSessionInfo, camera3::BufferRecords *bufferRecords) {
+ // Validate buffer caches
+ std::vector<int32_t> streams;
+ streams.reserve(offlineSessionInfo->offlineStreams.size());
+ for (auto offlineStream : offlineSessionInfo->offlineStreams) {
+ int32_t id = offlineStream.id;
+ streams.push_back(id);
+ // Verify buffer caches
+ std::vector<uint64_t> bufIds(offlineStream.circulatingBufferIds.begin(),
+ offlineStream.circulatingBufferIds.end());
+ if (!verifyBufferIds(id, bufIds)) {
+ ALOGE("%s: stream ID %d buffer cache records mismatch!", __FUNCTION__, id);
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ // Move buffer records
+ bufferRecords->takeBufferCaches(mBufferRecords, streams);
+ bufferRecords->takeInflightBufferMap(mBufferRecords);
+ bufferRecords->takeRequestedBufferMap(mBufferRecords);
+ return OK;
+ }
+
// Delete and optionally close native handles and clear the input vector afterward
static void cleanupNativeHandles(
std::vector<native_handle_t*> *handles, bool closeFd = false);
@@ -493,7 +464,7 @@
bool mIsReconfigurationQuerySupported;
const bool mSupportOfflineProcessing;
- };
+ }; // class HalInterface
sp<HalInterface> mInterface;
@@ -619,41 +590,6 @@
bool repeating,
int64_t *lastFrameNumber = NULL);
-
- /**
- * Implementation of android::hardware::camera::device::V3_5::ICameraDeviceCallback
- */
-
- hardware::Return<void> processCaptureResult_3_4(
- const hardware::hidl_vec<
- hardware::camera::device::V3_4::CaptureResult>& results) override;
- hardware::Return<void> processCaptureResult(
- const hardware::hidl_vec<
- hardware::camera::device::V3_2::CaptureResult>& results) override;
- hardware::Return<void> notify(
- const hardware::hidl_vec<
- hardware::camera::device::V3_2::NotifyMsg>& msgs) override;
-
- hardware::Return<void> requestStreamBuffers(
- const hardware::hidl_vec<
- hardware::camera::device::V3_5::BufferRequest>& bufReqs,
- requestStreamBuffers_cb _hidl_cb) override;
-
- hardware::Return<void> returnStreamBuffers(
- const hardware::hidl_vec<
- hardware::camera::device::V3_2::StreamBuffer>& buffers) override;
-
- hardware::Return<void> notify_3_8(
- const hardware::hidl_vec<
- hardware::camera::device::V3_8::NotifyMsg>& msgs) override;
-
- template<typename NotifyMsgType>
- hardware::Return<void> notifyHelper(
- const hardware::hidl_vec<NotifyMsgType>& msgs);
-
- // Handle one notify message
- void notify(const hardware::camera::device::V3_2::NotifyMsg& msg);
-
// lock to ensure only one processCaptureResult is called at a time.
Mutex mProcessCaptureResultLock;
@@ -671,6 +607,9 @@
*/
virtual CameraMetadata getLatestRequestLocked();
+ virtual status_t injectionCameraInitialize(const String8 &injectCamId,
+ sp<CameraProviderManager> manager) = 0;
+
/**
* Update the current device status and wake all waiting threads.
*
@@ -919,12 +858,6 @@
void signalPipelineDrain(const std::vector<int>& streamIds);
void resetPipelineDrain();
- status_t switchToOffline(
- const std::vector<int32_t>& streamsToKeep,
- /*out*/hardware::camera::device::V3_6::CameraOfflineSessionInfo* offlineSessionInfo,
- /*out*/sp<hardware::camera::device::V3_6::ICameraOfflineSession>* offlineSession,
- /*out*/camera3::BufferRecords* bufferRecords);
-
void clearPreviousRequest();
status_t setRotateAndCropAutoBehavior(
@@ -939,7 +872,6 @@
virtual bool threadLoop();
- private:
static const String8& getId(const wp<Camera3Device> &device);
status_t queueTriggerLocked(RequestTrigger trigger);
@@ -1104,6 +1036,14 @@
const bool mUseHalBufManager;
const bool mSupportCameraMute;
};
+
+ virtual sp<RequestThread> createNewRequestThread(wp<Camera3Device> /*parent*/,
+ sp<camera3::StatusTracker> /*statusTracker*/,
+ sp<HalInterface> /*interface*/,
+ const Vector<int32_t>& /*sessionParamKeys*/,
+ bool /*useHalBufManager*/,
+ bool /*supportCameraMute*/) = 0;
+
sp<RequestThread> mRequestThread;
/**
@@ -1379,13 +1319,6 @@
~Camera3DeviceInjectionMethods();
- // Initialize the injection camera and generate an hal interface.
- status_t injectionInitialize(
- const String8& injectedCamId, sp<CameraProviderManager> manager,
- const sp<
- android::hardware::camera::device::V3_2 ::ICameraDeviceCallback>&
- callback);
-
// Injection camera will replace the internal camera and configure streams
// when device is IDLE and request thread is paused.
status_t injectCamera(
@@ -1411,7 +1344,7 @@
const camera3::camera_stream_configuration& injectionConfig,
const std::vector<uint32_t>& injectionBufferSizes);
- private:
+ protected:
// Configure the streams of injection camera, it need wait until the
// output streams are created and configured to the original camera before
// proceeding.
@@ -1424,8 +1357,8 @@
// Use injection camera hal interface to replace and backup original
// camera hal interface.
- status_t replaceHalInterface(sp<HalInterface> newHalInterface,
- bool keepBackup);
+ virtual status_t replaceHalInterface(sp<HalInterface> /*newHalInterface*/,
+ bool /*keepBackup*/) = 0;
wp<Camera3Device> mParent;
@@ -1435,13 +1368,6 @@
// Generated injection camera hal interface.
sp<HalInterface> mInjectedCamHalInterface;
- // Backup of the original camera hal result FMQ.
- std::unique_ptr<ResultMetadataQueue> mBackupResultMetadataQueue;
-
- // FMQ writes the result for the injection camera. Must be guarded by
- // mProcessCaptureResultLock.
- std::unique_ptr<ResultMetadataQueue> mInjectionResultMetadataQueue;
-
// The flag indicates that the stream configuration is complete, the camera device is
// active, but the injection camera has not yet been injected.
bool mIsStreamConfigCompleteButNotInjected = false;
@@ -1462,6 +1388,10 @@
// The injection camera ID.
String8 mInjectedCamId;
};
+
+ virtual sp<Camera3DeviceInjectionMethods>
+ createCamera3DeviceInjectionMethods(wp<Camera3Device>) = 0;
+
sp<Camera3DeviceInjectionMethods> mInjectionMethods;
}; // class Camera3Device
diff --git a/services/camera/libcameraservice/device3/Camera3DeviceInjectionMethods.cpp b/services/camera/libcameraservice/device3/Camera3DeviceInjectionMethods.cpp
index 4744a6d..6818acf 100644
--- a/services/camera/libcameraservice/device3/Camera3DeviceInjectionMethods.cpp
+++ b/services/camera/libcameraservice/device3/Camera3DeviceInjectionMethods.cpp
@@ -39,92 +39,6 @@
injectionDisconnectImpl();
}
-status_t Camera3Device::Camera3DeviceInjectionMethods::injectionInitialize(
- const String8& injectedCamId, sp<CameraProviderManager> manager,
- const sp<android::hardware::camera::device::V3_2::ICameraDeviceCallback>&
- callback) {
- ATRACE_CALL();
- Mutex::Autolock lock(mInjectionLock);
-
- if (manager == nullptr) {
- ALOGE("%s: manager does not exist!", __FUNCTION__);
- return INVALID_OPERATION;
- }
-
- sp<Camera3Device> parent = mParent.promote();
- if (parent == nullptr) {
- ALOGE("%s: parent does not exist!", __FUNCTION__);
- return INVALID_OPERATION;
- }
-
- mInjectedCamId = injectedCamId;
- sp<ICameraDeviceSession> session;
- ATRACE_BEGIN("Injection CameraHal::openSession");
- status_t res = manager->openSession(injectedCamId.string(), callback,
- /*out*/ &session);
- ATRACE_END();
- if (res != OK) {
- ALOGE("Injection camera could not open camera session: %s (%d)",
- strerror(-res), res);
- return res;
- }
-
- std::shared_ptr<RequestMetadataQueue> queue;
- auto requestQueueRet =
- session->getCaptureRequestMetadataQueue([&queue](const auto& descriptor) {
- queue = std::make_shared<RequestMetadataQueue>(descriptor);
- if (!queue->isValid() || queue->availableToWrite() <= 0) {
- ALOGE("Injection camera HAL returns empty request metadata fmq, not "
- "use it");
- queue = nullptr;
- // don't use the queue onwards.
- }
- });
- if (!requestQueueRet.isOk()) {
- ALOGE("Injection camera transaction error when getting request metadata fmq: "
- "%s, not use it", requestQueueRet.description().c_str());
- return DEAD_OBJECT;
- }
-
- std::unique_ptr<ResultMetadataQueue>& resQueue = mInjectionResultMetadataQueue;
- auto resultQueueRet = session->getCaptureResultMetadataQueue(
- [&resQueue](const auto& descriptor) {
- resQueue = std::make_unique<ResultMetadataQueue>(descriptor);
- if (!resQueue->isValid() || resQueue->availableToWrite() <= 0) {
- ALOGE("Injection camera HAL returns empty result metadata fmq, not use "
- "it");
- resQueue = nullptr;
- // Don't use the resQueue onwards.
- }
- });
- if (!resultQueueRet.isOk()) {
- ALOGE("Injection camera transaction error when getting result metadata queue "
- "from camera session: %s", resultQueueRet.description().c_str());
- return DEAD_OBJECT;
- }
- IF_ALOGV() {
- session->interfaceChain(
- [](::android::hardware::hidl_vec<::android::hardware::hidl_string>
- interfaceChain) {
- ALOGV("Injection camera session interface chain:");
- for (const auto& iface : interfaceChain) {
- ALOGV(" %s", iface.c_str());
- }
- });
- }
-
- ALOGV("%s: Injection camera interface = new HalInterface()", __FUNCTION__);
- mInjectedCamHalInterface =
- new HalInterface(session, queue, parent->mUseHalBufManager,
- parent->mSupportOfflineProcessing);
- if (mInjectedCamHalInterface == nullptr) {
- ALOGE("%s: mInjectedCamHalInterface does not exist!", __FUNCTION__);
- return DEAD_OBJECT;
- }
-
- return OK;
-}
-
status_t Camera3Device::Camera3DeviceInjectionMethods::injectCamera(
camera3::camera_stream_configuration& injectionConfig,
const std::vector<uint32_t>& injectionBufferSizes) {
@@ -379,37 +293,4 @@
}
}
-status_t Camera3Device::Camera3DeviceInjectionMethods::replaceHalInterface(
- sp<HalInterface> newHalInterface, bool keepBackup) {
- Mutex::Autolock lock(mInjectionLock);
- if (newHalInterface.get() == nullptr) {
- ALOGE("%s: The newHalInterface does not exist, to stop replacing.",
- __FUNCTION__);
- return DEAD_OBJECT;
- }
-
- sp<Camera3Device> parent = mParent.promote();
- if (parent == nullptr) {
- ALOGE("%s: parent does not exist!", __FUNCTION__);
- return INVALID_OPERATION;
- }
-
- if (keepBackup) {
- if (mBackupHalInterface == nullptr) {
- mBackupHalInterface = parent->mInterface;
- }
- if (mBackupResultMetadataQueue == nullptr) {
- mBackupResultMetadataQueue = std::move(parent->mResultMetadataQueue);
- parent->mResultMetadataQueue = std::move(mInjectionResultMetadataQueue);
- }
- } else {
- mBackupHalInterface = nullptr;
- parent->mResultMetadataQueue = std::move(mBackupResultMetadataQueue);
- mBackupResultMetadataQueue = nullptr;
- }
- parent->mInterface = newHalInterface;
-
- return OK;
-}
-
}; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
index f4b3197..ba97367 100644
--- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
@@ -34,10 +34,11 @@
android_dataspace dataSpace, camera_stream_rotation_t rotation,
const String8& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
- int setId, bool isMultiResolution) :
+ int setId, bool isMultiResolution, int dynamicRangeProfile) :
Camera3Stream(id, type,
width, height, maxSize, format, dataSpace, rotation,
- physicalCameraId, sensorPixelModesUsed, setId, isMultiResolution),
+ physicalCameraId, sensorPixelModesUsed, setId, isMultiResolution,
+ dynamicRangeProfile),
mTotalBufferCount(0),
mHandoutTotalBufferCount(0),
mHandoutOutputBufferCount(0),
@@ -87,6 +88,7 @@
if (strlen(camera_stream::physical_camera_id) > 0) {
lines.appendFormat(" Physical camera id: %s\n", camera_stream::physical_camera_id);
}
+ lines.appendFormat(" Dynamic Range Profile: 0x%x", camera_stream::dynamic_range_profile);
lines.appendFormat(" Frames produced: %d, last timestamp: %" PRId64 " ns\n",
mFrameCount, mLastTimestamp);
lines.appendFormat(" Total buffers: %zu, currently dequeued: %zu\n",
diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
index fb73c97..518ee42 100644
--- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
@@ -37,7 +37,8 @@
android_dataspace dataSpace, camera_stream_rotation_t rotation,
const String8& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
- int setId = CAMERA3_STREAM_SET_ID_INVALID, bool isMultiResolution = false);
+ int setId = CAMERA3_STREAM_SET_ID_INVALID, bool isMultiResolution = false,
+ int dynamicProfile = ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD);
public:
diff --git a/services/camera/libcameraservice/device3/Camera3OfflineSession.cpp b/services/camera/libcameraservice/device3/Camera3OfflineSession.cpp
index b702e20..7cfa255 100644
--- a/services/camera/libcameraservice/device3/Camera3OfflineSession.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OfflineSession.cpp
@@ -47,14 +47,12 @@
const camera3::StreamSet& offlineStreamSet,
camera3::BufferRecords&& bufferRecords,
const camera3::InFlightRequestMap& offlineReqs,
- const Camera3OfflineStates& offlineStates,
- sp<hardware::camera::device::V3_6::ICameraOfflineSession> offlineSession) :
+ const Camera3OfflineStates& offlineStates) :
mId(id),
mInputStream(inputStream),
mOutputStreams(offlineStreamSet),
mBufferRecords(std::move(bufferRecords)),
mOfflineReqs(offlineReqs),
- mSession(offlineSession),
mTagMonitor(offlineStates.mTagMonitor),
mVendorTagId(offlineStates.mVendorTagId),
mUseHalBufManager(offlineStates.mUseHalBufManager),
@@ -90,43 +88,6 @@
return mId;
}
-status_t Camera3OfflineSession::initialize(wp<NotificationListener> listener) {
- ATRACE_CALL();
-
- if (mSession == nullptr) {
- ALOGE("%s: HIDL session is null!", __FUNCTION__);
- return DEAD_OBJECT;
- }
-
- {
- std::lock_guard<std::mutex> lock(mLock);
-
- mListener = listener;
-
- // setup result FMQ
- std::unique_ptr<ResultMetadataQueue>& resQueue = mResultMetadataQueue;
- auto resultQueueRet = mSession->getCaptureResultMetadataQueue(
- [&resQueue](const auto& descriptor) {
- resQueue = std::make_unique<ResultMetadataQueue>(descriptor);
- if (!resQueue->isValid() || resQueue->availableToWrite() <= 0) {
- ALOGE("HAL returns empty result metadata fmq, not use it");
- resQueue = nullptr;
- // Don't use resQueue onwards.
- }
- });
- if (!resultQueueRet.isOk()) {
- ALOGE("Transaction error when getting result metadata queue from camera session: %s",
- resultQueueRet.description().c_str());
- return DEAD_OBJECT;
- }
- mStatus = STATUS_ACTIVE;
- }
-
- mSession->setCallback(this);
-
- return OK;
-}
-
status_t Camera3OfflineSession::dump(int /*fd*/) {
ATRACE_CALL();
std::lock_guard<std::mutex> il(mInterfaceLock);
@@ -135,6 +96,7 @@
status_t Camera3OfflineSession::disconnect() {
ATRACE_CALL();
+ disconnectSession();
return disconnectImpl();
}
@@ -170,10 +132,6 @@
streams.push_back(mInputStream);
}
- if (mSession != nullptr) {
- mSession->close();
- }
-
FlushInflightReqStates states {
mId, mOfflineReqsLock, mOfflineReqs, mUseHalBufManager,
listener, *this, mBufferRecords, *this, mSessionStatsBuilder};
@@ -182,7 +140,6 @@
{
std::lock_guard<std::mutex> lock(mLock);
- mSession.clear();
mOutputStreams.clear();
mInputStream.clear();
mStatus = STATUS_CLOSED;
@@ -235,149 +192,6 @@
return OK;
}
-hardware::Return<void> Camera3OfflineSession::processCaptureResult_3_4(
- const hardware::hidl_vec<
- hardware::camera::device::V3_4::CaptureResult>& results) {
- sp<NotificationListener> listener;
- {
- std::lock_guard<std::mutex> lock(mLock);
- if (mStatus != STATUS_ACTIVE) {
- ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
- return hardware::Void();
- }
- listener = mListener.promote();
- }
-
- CaptureOutputStates states {
- mId,
- mOfflineReqsLock, mLastCompletedRegularFrameNumber,
- mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
- mOfflineReqs, mOutputLock, mResultQueue, mResultSignal,
- mNextShutterFrameNumber,
- mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
- mNextResultFrameNumber,
- mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
- mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
- mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
- mResultMetadataQueue, mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
- mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
- mBufferRecords, /*legacyClient*/ false
- };
-
- std::lock_guard<std::mutex> lock(mProcessCaptureResultLock);
- for (const auto& result : results) {
- processOneCaptureResultLocked(states, result.v3_2, result.physicalCameraMetadata);
- }
- return hardware::Void();
-}
-
-hardware::Return<void> Camera3OfflineSession::processCaptureResult(
- const hardware::hidl_vec<
- hardware::camera::device::V3_2::CaptureResult>& results) {
- // TODO: changed impl to call into processCaptureResult_3_4 instead?
- // might need to figure how to reduce copy though.
- sp<NotificationListener> listener;
- {
- std::lock_guard<std::mutex> lock(mLock);
- if (mStatus != STATUS_ACTIVE) {
- ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
- return hardware::Void();
- }
- listener = mListener.promote();
- }
-
- hardware::hidl_vec<hardware::camera::device::V3_4::PhysicalCameraMetadata> noPhysMetadata;
-
- CaptureOutputStates states {
- mId,
- mOfflineReqsLock, mLastCompletedRegularFrameNumber,
- mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
- mOfflineReqs, mOutputLock, mResultQueue, mResultSignal,
- mNextShutterFrameNumber,
- mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
- mNextResultFrameNumber,
- mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
- mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
- mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
- mResultMetadataQueue, mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
- mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
- mBufferRecords, /*legacyClient*/ false
- };
-
- std::lock_guard<std::mutex> lock(mProcessCaptureResultLock);
- for (const auto& result : results) {
- processOneCaptureResultLocked(states, result, noPhysMetadata);
- }
- return hardware::Void();
-}
-
-hardware::Return<void> Camera3OfflineSession::notify(
- const hardware::hidl_vec<hardware::camera::device::V3_2::NotifyMsg>& msgs) {
- sp<NotificationListener> listener;
- {
- std::lock_guard<std::mutex> lock(mLock);
- if (mStatus != STATUS_ACTIVE) {
- ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
- return hardware::Void();
- }
- listener = mListener.promote();
- }
-
- CaptureOutputStates states {
- mId,
- mOfflineReqsLock, mLastCompletedRegularFrameNumber,
- mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
- mOfflineReqs, mOutputLock, mResultQueue, mResultSignal,
- mNextShutterFrameNumber,
- mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
- mNextResultFrameNumber,
- mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
- mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
- mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
- mResultMetadataQueue, mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
- mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
- mBufferRecords, /*legacyClient*/ false
- };
- for (const auto& msg : msgs) {
- camera3::notify(states, msg);
- }
- return hardware::Void();
-}
-
-hardware::Return<void> Camera3OfflineSession::requestStreamBuffers(
- const hardware::hidl_vec<hardware::camera::device::V3_5::BufferRequest>& bufReqs,
- requestStreamBuffers_cb _hidl_cb) {
- {
- std::lock_guard<std::mutex> lock(mLock);
- if (mStatus != STATUS_ACTIVE) {
- ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
- return hardware::Void();
- }
- }
-
- RequestBufferStates states {
- mId, mRequestBufferInterfaceLock, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder,
- *this, mBufferRecords, *this};
- camera3::requestStreamBuffers(states, bufReqs, _hidl_cb);
- return hardware::Void();
-}
-
-hardware::Return<void> Camera3OfflineSession::returnStreamBuffers(
- const hardware::hidl_vec<hardware::camera::device::V3_2::StreamBuffer>& buffers) {
- {
- std::lock_guard<std::mutex> lock(mLock);
- if (mStatus != STATUS_ACTIVE) {
- ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
- return hardware::Void();
- }
- }
-
- ReturnBufferStates states {
- mId, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder, mBufferRecords};
- camera3::returnStreamBuffers(states, buffers);
- return hardware::Void();
-}
-
void Camera3OfflineSession::setErrorState(const char *fmt, ...) {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mLock);
diff --git a/services/camera/libcameraservice/device3/Camera3OfflineSession.h b/services/camera/libcameraservice/device3/Camera3OfflineSession.h
index 5581964..0f7d145 100644
--- a/services/camera/libcameraservice/device3/Camera3OfflineSession.h
+++ b/services/camera/libcameraservice/device3/Camera3OfflineSession.h
@@ -131,7 +131,6 @@
*/
class Camera3OfflineSession :
public CameraOfflineSessionBase,
- virtual public hardware::camera::device::V3_5::ICameraDeviceCallback,
public camera3::SetErrorInterface,
public camera3::InflightRequestUpdateInterface,
public camera3::RequestBufferInterface,
@@ -144,12 +143,11 @@
const camera3::StreamSet& offlineStreamSet,
camera3::BufferRecords&& bufferRecords,
const camera3::InFlightRequestMap& offlineReqs,
- const Camera3OfflineStates& offlineStates,
- sp<hardware::camera::device::V3_6::ICameraOfflineSession> offlineSession);
+ const Camera3OfflineStates& offlineStates);
virtual ~Camera3OfflineSession();
- virtual status_t initialize(wp<NotificationListener> listener) override;
+ virtual status_t initialize(wp<NotificationListener> /*listener*/) = 0;
/**
* CameraOfflineSessionBase interface
@@ -171,38 +169,7 @@
* End of CameraOfflineSessionBase interface
*/
- /**
- * HIDL ICameraDeviceCallback interface
- */
-
- /**
- * Implementation of android::hardware::camera::device::V3_5::ICameraDeviceCallback
- */
-
- hardware::Return<void> processCaptureResult_3_4(
- const hardware::hidl_vec<
- hardware::camera::device::V3_4::CaptureResult>& results) override;
- hardware::Return<void> processCaptureResult(
- const hardware::hidl_vec<
- hardware::camera::device::V3_2::CaptureResult>& results) override;
- hardware::Return<void> notify(
- const hardware::hidl_vec<
- hardware::camera::device::V3_2::NotifyMsg>& msgs) override;
-
- hardware::Return<void> requestStreamBuffers(
- const hardware::hidl_vec<
- hardware::camera::device::V3_5::BufferRequest>& bufReqs,
- requestStreamBuffers_cb _hidl_cb) override;
-
- hardware::Return<void> returnStreamBuffers(
- const hardware::hidl_vec<
- hardware::camera::device::V3_2::StreamBuffer>& buffers) override;
-
- /**
- * End of CameraOfflineSessionBase interface
- */
-
- private:
+ protected:
// Camera device ID
const String8 mId;
sp<camera3::Camera3Stream> mInputStream;
@@ -213,8 +180,6 @@
std::mutex mOfflineReqsLock;
camera3::InFlightRequestMap mOfflineReqs;
- sp<hardware::camera::device::V3_6::ICameraOfflineSession> mSession;
-
TagMonitor mTagMonitor;
const metadata_vendor_id_t mVendorTagId;
@@ -269,8 +234,6 @@
// End of mLock protect scope
std::mutex mProcessCaptureResultLock;
- // FMQ to write result on. Must be guarded by mProcessCaptureResultLock.
- std::unique_ptr<ResultMetadataQueue> mResultMetadataQueue;
// Tracking cause of fatal errors when in STATUS_ERROR
String8 mErrorCause;
@@ -305,6 +268,8 @@
void setErrorStateLockedV(const char *fmt, va_list args);
status_t disconnectImpl();
+ virtual void disconnectSession() = 0;
+
}; // class Camera3OfflineSession
}; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index 0dfeac3..69723b6 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -46,10 +46,11 @@
android_dataspace dataSpace, camera_stream_rotation_t rotation,
nsecs_t timestampOffset, const String8& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
- int setId, bool isMultiResolution) :
+ int setId, bool isMultiResolution, int dynamicRangeProfile) :
Camera3IOStreamBase(id, CAMERA_STREAM_OUTPUT, width, height,
/*maxSize*/0, format, dataSpace, rotation,
- physicalCameraId, sensorPixelModesUsed, setId, isMultiResolution),
+ physicalCameraId, sensorPixelModesUsed, setId, isMultiResolution,
+ dynamicRangeProfile),
mConsumer(consumer),
mTransform(0),
mTraceFirstBuffer(true),
@@ -74,10 +75,10 @@
android_dataspace dataSpace, camera_stream_rotation_t rotation,
nsecs_t timestampOffset, const String8& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
- int setId, bool isMultiResolution) :
+ int setId, bool isMultiResolution, int dynamicRangeProfile) :
Camera3IOStreamBase(id, CAMERA_STREAM_OUTPUT, width, height, maxSize,
format, dataSpace, rotation, physicalCameraId, sensorPixelModesUsed,
- setId, isMultiResolution),
+ setId, isMultiResolution, dynamicRangeProfile),
mConsumer(consumer),
mTransform(0),
mTraceFirstBuffer(true),
@@ -109,10 +110,11 @@
camera_stream_rotation_t rotation, nsecs_t timestampOffset,
const String8& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
- int setId, bool isMultiResolution) :
+ int setId, bool isMultiResolution, int dynamicRangeProfile) :
Camera3IOStreamBase(id, CAMERA_STREAM_OUTPUT, width, height,
/*maxSize*/0, format, dataSpace, rotation,
- physicalCameraId, sensorPixelModesUsed, setId, isMultiResolution),
+ physicalCameraId, sensorPixelModesUsed, setId, isMultiResolution,
+ dynamicRangeProfile),
mConsumer(nullptr),
mTransform(0),
mTraceFirstBuffer(true),
@@ -149,11 +151,13 @@
const String8& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
uint64_t consumerUsage, nsecs_t timestampOffset,
- int setId, bool isMultiResolution) :
+ int setId, bool isMultiResolution,
+ int dynamicRangeProfile) :
Camera3IOStreamBase(id, type, width, height,
/*maxSize*/0,
format, dataSpace, rotation,
- physicalCameraId, sensorPixelModesUsed, setId, isMultiResolution),
+ physicalCameraId, sensorPixelModesUsed, setId, isMultiResolution,
+ dynamicRangeProfile),
mTransform(0),
mTraceFirstBuffer(true),
mUseMonoTimestamp(false),
@@ -379,6 +383,9 @@
__FUNCTION__, mId, strerror(-res), res);
return res;
}
+
+ queueHDRMetadata(anwBuffer->handle, currentConsumer, dynamic_range_profile);
+
res = queueBufferToConsumer(currentConsumer, anwBuffer, anwReleaseFence, surface_ids);
if (shouldLogError(res, state)) {
ALOGE("%s: Stream %d: Error queueing buffer to native window:"
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index a70b883..d9bf62a 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -89,7 +89,8 @@
android_dataspace dataSpace, camera_stream_rotation_t rotation,
nsecs_t timestampOffset, const String8& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
- int setId = CAMERA3_STREAM_SET_ID_INVALID, bool isMultiResolution = false);
+ int setId = CAMERA3_STREAM_SET_ID_INVALID, bool isMultiResolution = false,
+ int dynamicProfile = ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD);
/**
* Set up a stream for formats that have a variable buffer size for the same
* dimensions, such as compressed JPEG.
@@ -101,7 +102,8 @@
android_dataspace dataSpace, camera_stream_rotation_t rotation,
nsecs_t timestampOffset, const String8& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
- int setId = CAMERA3_STREAM_SET_ID_INVALID, bool isMultiResolution = false);
+ int setId = CAMERA3_STREAM_SET_ID_INVALID, bool isMultiResolution = false,
+ int dynamicProfile = ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD);
/**
* Set up a stream with deferred consumer for formats that have 2 dimensions, such as
* RAW and YUV. The consumer must be set before using this stream for output. A valid
@@ -112,7 +114,8 @@
camera_stream_rotation_t rotation, nsecs_t timestampOffset,
const String8& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
- int setId = CAMERA3_STREAM_SET_ID_INVALID, bool isMultiResolution = false);
+ int setId = CAMERA3_STREAM_SET_ID_INVALID, bool isMultiResolution = false,
+ int dynamicProfile = ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD);
virtual ~Camera3OutputStream();
@@ -239,7 +242,8 @@
const String8& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
uint64_t consumerUsage = 0, nsecs_t timestampOffset = 0,
- int setId = CAMERA3_STREAM_SET_ID_INVALID, bool isMultiResolution = false);
+ int setId = CAMERA3_STREAM_SET_ID_INVALID, bool isMultiResolution = false,
+ int dynamicProfile = ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD);
/**
* Note that we release the lock briefly in this function
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
index 5e4f38a..d8cc685 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
@@ -376,43 +376,6 @@
insertResultLocked(states, &captureResult, frameNumber);
}
-// Reading one camera metadata from result argument via fmq or from the result
-// Assuming the fmq is protected by a lock already
-status_t readOneCameraMetadataLocked(
- std::unique_ptr<ResultMetadataQueue>& fmq,
- uint64_t fmqResultSize,
- hardware::camera::device::V3_2::CameraMetadata& resultMetadata,
- const hardware::camera::device::V3_2::CameraMetadata& result) {
- if (fmqResultSize > 0) {
- resultMetadata.resize(fmqResultSize);
- if (fmq == nullptr) {
- return NO_MEMORY; // logged in initialize()
- }
- if (!fmq->read(resultMetadata.data(), fmqResultSize)) {
- ALOGE("%s: Cannot read camera metadata from fmq, size = %" PRIu64,
- __FUNCTION__, fmqResultSize);
- return INVALID_OPERATION;
- }
- } else {
- resultMetadata.setToExternal(const_cast<uint8_t *>(result.data()),
- result.size());
- }
-
- if (resultMetadata.size() != 0) {
- status_t res;
- const camera_metadata_t* metadata =
- reinterpret_cast<const camera_metadata_t*>(resultMetadata.data());
- size_t expected_metadata_size = resultMetadata.size();
- if ((res = validate_camera_metadata_structure(metadata, &expected_metadata_size)) != OK) {
- ALOGE("%s: Invalid camera metadata received by camera service from HAL: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- return INVALID_OPERATION;
- }
- }
-
- return OK;
-}
-
void removeInFlightMapEntryLocked(CaptureOutputStates& states, int idx) {
ATRACE_CALL();
InFlightRequestMap& inflightMap = states.inflightMap;
@@ -472,7 +435,7 @@
// Note down the just completed frame number
if (request.hasInputBuffer) {
states.lastCompletedReprocessFrameNumber = frameNumber;
- } else if (request.zslCapture) {
+ } else if (request.zslCapture && request.stillCapture) {
states.lastCompletedZslFrameNumber = frameNumber;
} else {
states.lastCompletedRegularFrameNumber = frameNumber;
@@ -719,153 +682,6 @@
}
}
-void processOneCaptureResultLocked(
- CaptureOutputStates& states,
- const hardware::camera::device::V3_2::CaptureResult& result,
- const hardware::hidl_vec<
- hardware::camera::device::V3_4::PhysicalCameraMetadata> physicalCameraMetadata) {
- using hardware::camera::device::V3_2::StreamBuffer;
- using hardware::camera::device::V3_2::BufferStatus;
- std::unique_ptr<ResultMetadataQueue>& fmq = states.fmq;
- BufferRecordsInterface& bufferRecords = states.bufferRecordsIntf;
- camera_capture_result r;
- status_t res;
- r.frame_number = result.frameNumber;
-
- // Read and validate the result metadata.
- hardware::camera::device::V3_2::CameraMetadata resultMetadata;
- res = readOneCameraMetadataLocked(
- fmq, result.fmqResultSize,
- resultMetadata, result.result);
- if (res != OK) {
- ALOGE("%s: Frame %d: Failed to read capture result metadata",
- __FUNCTION__, result.frameNumber);
- return;
- }
- r.result = reinterpret_cast<const camera_metadata_t*>(resultMetadata.data());
-
- // Read and validate physical camera metadata
- size_t physResultCount = physicalCameraMetadata.size();
- std::vector<const char*> physCamIds(physResultCount);
- std::vector<const camera_metadata_t *> phyCamMetadatas(physResultCount);
- std::vector<hardware::camera::device::V3_2::CameraMetadata> physResultMetadata;
- physResultMetadata.resize(physResultCount);
- for (size_t i = 0; i < physicalCameraMetadata.size(); i++) {
- res = readOneCameraMetadataLocked(fmq, physicalCameraMetadata[i].fmqMetadataSize,
- physResultMetadata[i], physicalCameraMetadata[i].metadata);
- if (res != OK) {
- ALOGE("%s: Frame %d: Failed to read capture result metadata for camera %s",
- __FUNCTION__, result.frameNumber,
- physicalCameraMetadata[i].physicalCameraId.c_str());
- return;
- }
- physCamIds[i] = physicalCameraMetadata[i].physicalCameraId.c_str();
- phyCamMetadatas[i] = reinterpret_cast<const camera_metadata_t*>(
- physResultMetadata[i].data());
- }
- r.num_physcam_metadata = physResultCount;
- r.physcam_ids = physCamIds.data();
- r.physcam_metadata = phyCamMetadatas.data();
-
- std::vector<camera_stream_buffer_t> outputBuffers(result.outputBuffers.size());
- std::vector<buffer_handle_t> outputBufferHandles(result.outputBuffers.size());
- for (size_t i = 0; i < result.outputBuffers.size(); i++) {
- auto& bDst = outputBuffers[i];
- const StreamBuffer &bSrc = result.outputBuffers[i];
-
- sp<Camera3StreamInterface> stream = states.outputStreams.get(bSrc.streamId);
- if (stream == nullptr) {
- ALOGE("%s: Frame %d: Buffer %zu: Invalid output stream id %d",
- __FUNCTION__, result.frameNumber, i, bSrc.streamId);
- return;
- }
- bDst.stream = stream->asHalStream();
-
- bool noBufferReturned = false;
- buffer_handle_t *buffer = nullptr;
- if (states.useHalBufManager) {
- // This is suspicious most of the time but can be correct during flush where HAL
- // has to return capture result before a buffer is requested
- if (bSrc.bufferId == BUFFER_ID_NO_BUFFER) {
- if (bSrc.status == BufferStatus::OK) {
- ALOGE("%s: Frame %d: Buffer %zu: No bufferId for stream %d",
- __FUNCTION__, result.frameNumber, i, bSrc.streamId);
- // Still proceeds so other buffers can be returned
- }
- noBufferReturned = true;
- }
- if (noBufferReturned) {
- res = OK;
- } else {
- res = bufferRecords.popInflightRequestBuffer(bSrc.bufferId, &buffer);
- }
- } else {
- res = bufferRecords.popInflightBuffer(result.frameNumber, bSrc.streamId, &buffer);
- }
-
- if (res != OK) {
- ALOGE("%s: Frame %d: Buffer %zu: No in-flight buffer for stream %d",
- __FUNCTION__, result.frameNumber, i, bSrc.streamId);
- return;
- }
-
- bDst.buffer = buffer;
- bDst.status = mapHidlBufferStatus(bSrc.status);
- bDst.acquire_fence = -1;
- if (bSrc.releaseFence == nullptr) {
- bDst.release_fence = -1;
- } else if (bSrc.releaseFence->numFds == 1) {
- if (noBufferReturned) {
- ALOGE("%s: got releaseFence without output buffer!", __FUNCTION__);
- }
- bDst.release_fence = dup(bSrc.releaseFence->data[0]);
- } else {
- ALOGE("%s: Frame %d: Invalid release fence for buffer %zu, fd count is %d, not 1",
- __FUNCTION__, result.frameNumber, i, bSrc.releaseFence->numFds);
- return;
- }
- }
- r.num_output_buffers = outputBuffers.size();
- r.output_buffers = outputBuffers.data();
-
- camera_stream_buffer_t inputBuffer;
- if (result.inputBuffer.streamId == -1) {
- r.input_buffer = nullptr;
- } else {
- if (states.inputStream->getId() != result.inputBuffer.streamId) {
- ALOGE("%s: Frame %d: Invalid input stream id %d", __FUNCTION__,
- result.frameNumber, result.inputBuffer.streamId);
- return;
- }
- inputBuffer.stream = states.inputStream->asHalStream();
- buffer_handle_t *buffer;
- res = bufferRecords.popInflightBuffer(result.frameNumber, result.inputBuffer.streamId,
- &buffer);
- if (res != OK) {
- ALOGE("%s: Frame %d: Input buffer: No in-flight buffer for stream %d",
- __FUNCTION__, result.frameNumber, result.inputBuffer.streamId);
- return;
- }
- inputBuffer.buffer = buffer;
- inputBuffer.status = mapHidlBufferStatus(result.inputBuffer.status);
- inputBuffer.acquire_fence = -1;
- if (result.inputBuffer.releaseFence == nullptr) {
- inputBuffer.release_fence = -1;
- } else if (result.inputBuffer.releaseFence->numFds == 1) {
- inputBuffer.release_fence = dup(result.inputBuffer.releaseFence->data[0]);
- } else {
- ALOGE("%s: Frame %d: Invalid release fence for input buffer, fd count is %d, not 1",
- __FUNCTION__, result.frameNumber, result.inputBuffer.releaseFence->numFds);
- return;
- }
- r.input_buffer = &inputBuffer;
- }
-
- r.partial_result = result.partialResult;
-
- processCaptureResult(states, &r);
-}
-
void returnOutputBuffers(
bool useHalBufManager,
sp<NotificationListener> listener,
@@ -969,7 +785,8 @@
void returnAndRemovePendingOutputBuffers(bool useHalBufManager,
sp<NotificationListener> listener, InFlightRequest& request,
SessionStatsBuilder& sessionStatsBuilder) {
- bool timestampIncreasing = !(request.zslCapture || request.hasInputBuffer);
+ bool timestampIncreasing =
+ !((request.zslCapture && request.stillCapture) || request.hasInputBuffer);
returnOutputBuffers(useHalBufManager, listener,
request.pendingOutputBuffers.array(),
request.pendingOutputBuffers.size(),
@@ -1193,330 +1010,6 @@
}
}
-void notify(CaptureOutputStates& states,
- const hardware::camera::device::V3_8::NotifyMsg& msg) {
- using android::hardware::camera::device::V3_2::MsgType;
-
- hardware::camera::device::V3_2::NotifyMsg msg_3_2;
- msg_3_2.type = msg.type;
- bool hasReadoutTime = false;
- uint64_t readoutTime = 0;
- switch (msg.type) {
- case MsgType::ERROR:
- msg_3_2.msg.error = msg.msg.error;
- break;
- case MsgType::SHUTTER:
- msg_3_2.msg.shutter = msg.msg.shutter.v3_2;
- hasReadoutTime = true;
- readoutTime = msg.msg.shutter.readoutTimestamp;
- break;
- }
- notify(states, msg_3_2, hasReadoutTime, readoutTime);
-}
-
-void notify(CaptureOutputStates& states,
- const hardware::camera::device::V3_2::NotifyMsg& msg,
- bool hasReadoutTime, uint64_t readoutTime) {
-
- using android::hardware::camera::device::V3_2::MsgType;
- using android::hardware::camera::device::V3_2::ErrorCode;
-
- ATRACE_CALL();
- camera_notify_msg m;
- switch (msg.type) {
- case MsgType::ERROR:
- m.type = CAMERA_MSG_ERROR;
- m.message.error.frame_number = msg.msg.error.frameNumber;
- if (msg.msg.error.errorStreamId >= 0) {
- sp<Camera3StreamInterface> stream =
- states.outputStreams.get(msg.msg.error.errorStreamId);
- if (stream == nullptr) {
- ALOGE("%s: Frame %d: Invalid error stream id %d", __FUNCTION__,
- m.message.error.frame_number, msg.msg.error.errorStreamId);
- return;
- }
- m.message.error.error_stream = stream->asHalStream();
- } else {
- m.message.error.error_stream = nullptr;
- }
- switch (msg.msg.error.errorCode) {
- case ErrorCode::ERROR_DEVICE:
- m.message.error.error_code = CAMERA_MSG_ERROR_DEVICE;
- break;
- case ErrorCode::ERROR_REQUEST:
- m.message.error.error_code = CAMERA_MSG_ERROR_REQUEST;
- break;
- case ErrorCode::ERROR_RESULT:
- m.message.error.error_code = CAMERA_MSG_ERROR_RESULT;
- break;
- case ErrorCode::ERROR_BUFFER:
- m.message.error.error_code = CAMERA_MSG_ERROR_BUFFER;
- break;
- }
- break;
- case MsgType::SHUTTER:
- m.type = CAMERA_MSG_SHUTTER;
- m.message.shutter.frame_number = msg.msg.shutter.frameNumber;
- m.message.shutter.timestamp = msg.msg.shutter.timestamp;
- m.message.shutter.readout_timestamp = hasReadoutTime ?
- readoutTime : m.message.shutter.timestamp;
- break;
- }
- notify(states, &m);
-}
-
-// The buffers requested through this call are not tied to any CaptureRequest in
-// particular. They may used by the hal for a particular frame's output buffer
-// or for its internal use as well. In the case that the hal does use any buffer
-// from the requested list here, for a particular frame's output buffer, the
-// buffer will be returned with the processCaptureResult call corresponding to
-// the frame. The other buffers will be returned through returnStreamBuffers.
-// The buffers returned via returnStreamBuffers will not have a valid
-// timestamp(0) and will be dropped by the bufferqueue.
-void requestStreamBuffers(RequestBufferStates& states,
- const hardware::hidl_vec<hardware::camera::device::V3_5::BufferRequest>& bufReqs,
- hardware::camera::device::V3_5::ICameraDeviceCallback::requestStreamBuffers_cb _hidl_cb) {
- using android::hardware::camera::device::V3_2::BufferStatus;
- using android::hardware::camera::device::V3_2::StreamBuffer;
- using android::hardware::camera::device::V3_5::BufferRequestStatus;
- using android::hardware::camera::device::V3_5::StreamBufferRet;
- using android::hardware::camera::device::V3_5::StreamBufferRequestError;
-
- std::lock_guard<std::mutex> lock(states.reqBufferLock);
-
- hardware::hidl_vec<StreamBufferRet> bufRets;
- if (!states.useHalBufManager) {
- ALOGE("%s: Camera %s does not support HAL buffer management",
- __FUNCTION__, states.cameraId.string());
- _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets);
- return;
- }
-
- SortedVector<int32_t> streamIds;
- ssize_t sz = streamIds.setCapacity(bufReqs.size());
- if (sz < 0 || static_cast<size_t>(sz) != bufReqs.size()) {
- ALOGE("%s: failed to allocate memory for %zu buffer requests",
- __FUNCTION__, bufReqs.size());
- _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets);
- return;
- }
-
- if (bufReqs.size() > states.outputStreams.size()) {
- ALOGE("%s: too many buffer requests (%zu > # of output streams %zu)",
- __FUNCTION__, bufReqs.size(), states.outputStreams.size());
- _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets);
- return;
- }
-
- // Check for repeated streamId
- for (const auto& bufReq : bufReqs) {
- if (streamIds.indexOf(bufReq.streamId) != NAME_NOT_FOUND) {
- ALOGE("%s: Stream %d appear multiple times in buffer requests",
- __FUNCTION__, bufReq.streamId);
- _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets);
- return;
- }
- streamIds.add(bufReq.streamId);
- }
-
- if (!states.reqBufferIntf.startRequestBuffer()) {
- ALOGE("%s: request buffer disallowed while camera service is configuring",
- __FUNCTION__);
- _hidl_cb(BufferRequestStatus::FAILED_CONFIGURING, bufRets);
- return;
- }
-
- bufRets.resize(bufReqs.size());
-
- bool allReqsSucceeds = true;
- bool oneReqSucceeds = false;
- for (size_t i = 0; i < bufReqs.size(); i++) {
- const auto& bufReq = bufReqs[i];
- auto& bufRet = bufRets[i];
- int32_t streamId = bufReq.streamId;
- sp<Camera3OutputStreamInterface> outputStream = states.outputStreams.get(streamId);
- if (outputStream == nullptr) {
- ALOGE("%s: Output stream id %d not found!", __FUNCTION__, streamId);
- hardware::hidl_vec<StreamBufferRet> emptyBufRets;
- _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, emptyBufRets);
- states.reqBufferIntf.endRequestBuffer();
- return;
- }
-
- bufRet.streamId = streamId;
- if (outputStream->isAbandoned()) {
- bufRet.val.error(StreamBufferRequestError::STREAM_DISCONNECTED);
- allReqsSucceeds = false;
- continue;
- }
-
- size_t handOutBufferCount = outputStream->getOutstandingBuffersCount();
- uint32_t numBuffersRequested = bufReq.numBuffersRequested;
- size_t totalHandout = handOutBufferCount + numBuffersRequested;
- uint32_t maxBuffers = outputStream->asHalStream()->max_buffers;
- if (totalHandout > maxBuffers) {
- // Not able to allocate enough buffer. Exit early for this stream
- ALOGE("%s: request too much buffers for stream %d: at HAL: %zu + requesting: %d"
- " > max: %d", __FUNCTION__, streamId, handOutBufferCount,
- numBuffersRequested, maxBuffers);
- bufRet.val.error(StreamBufferRequestError::MAX_BUFFER_EXCEEDED);
- allReqsSucceeds = false;
- continue;
- }
-
- hardware::hidl_vec<StreamBuffer> tmpRetBuffers(numBuffersRequested);
- bool currentReqSucceeds = true;
- std::vector<camera_stream_buffer_t> streamBuffers(numBuffersRequested);
- std::vector<buffer_handle_t> newBuffers;
- size_t numAllocatedBuffers = 0;
- size_t numPushedInflightBuffers = 0;
- for (size_t b = 0; b < numBuffersRequested; b++) {
- camera_stream_buffer_t& sb = streamBuffers[b];
- // Since this method can run concurrently with request thread
- // We need to update the wait duration everytime we call getbuffer
- nsecs_t waitDuration = states.reqBufferIntf.getWaitDuration();
- status_t res = outputStream->getBuffer(&sb, waitDuration);
- if (res != OK) {
- if (res == NO_INIT || res == DEAD_OBJECT) {
- ALOGV("%s: Can't get output buffer for stream %d: %s (%d)",
- __FUNCTION__, streamId, strerror(-res), res);
- bufRet.val.error(StreamBufferRequestError::STREAM_DISCONNECTED);
- states.sessionStatsBuilder.stopCounter(streamId);
- } else {
- ALOGE("%s: Can't get output buffer for stream %d: %s (%d)",
- __FUNCTION__, streamId, strerror(-res), res);
- if (res == TIMED_OUT || res == NO_MEMORY) {
- bufRet.val.error(StreamBufferRequestError::NO_BUFFER_AVAILABLE);
- } else {
- bufRet.val.error(StreamBufferRequestError::UNKNOWN_ERROR);
- }
- }
- currentReqSucceeds = false;
- break;
- }
- numAllocatedBuffers++;
-
- buffer_handle_t *buffer = sb.buffer;
- auto pair = states.bufferRecordsIntf.getBufferId(*buffer, streamId);
- bool isNewBuffer = pair.first;
- uint64_t bufferId = pair.second;
- StreamBuffer& hBuf = tmpRetBuffers[b];
-
- hBuf.streamId = streamId;
- hBuf.bufferId = bufferId;
- hBuf.buffer = (isNewBuffer) ? *buffer : nullptr;
- hBuf.status = BufferStatus::OK;
- hBuf.releaseFence = nullptr;
- if (isNewBuffer) {
- newBuffers.push_back(*buffer);
- }
-
- native_handle_t *acquireFence = nullptr;
- if (sb.acquire_fence != -1) {
- acquireFence = native_handle_create(1,0);
- acquireFence->data[0] = sb.acquire_fence;
- }
- hBuf.acquireFence.setTo(acquireFence, /*shouldOwn*/true);
- hBuf.releaseFence = nullptr;
-
- res = states.bufferRecordsIntf.pushInflightRequestBuffer(bufferId, buffer, streamId);
- if (res != OK) {
- ALOGE("%s: Can't get register request buffers for stream %d: %s (%d)",
- __FUNCTION__, streamId, strerror(-res), res);
- bufRet.val.error(StreamBufferRequestError::UNKNOWN_ERROR);
- currentReqSucceeds = false;
- break;
- }
- numPushedInflightBuffers++;
- }
- if (currentReqSucceeds) {
- bufRet.val.buffers(std::move(tmpRetBuffers));
- oneReqSucceeds = true;
- } else {
- allReqsSucceeds = false;
- for (size_t b = 0; b < numPushedInflightBuffers; b++) {
- StreamBuffer& hBuf = tmpRetBuffers[b];
- buffer_handle_t* buffer;
- status_t res = states.bufferRecordsIntf.popInflightRequestBuffer(
- hBuf.bufferId, &buffer);
- if (res != OK) {
- SET_ERR("%s: popInflightRequestBuffer failed for stream %d: %s (%d)",
- __FUNCTION__, streamId, strerror(-res), res);
- }
- }
- for (size_t b = 0; b < numAllocatedBuffers; b++) {
- camera_stream_buffer_t& sb = streamBuffers[b];
- sb.acquire_fence = -1;
- sb.status = CAMERA_BUFFER_STATUS_ERROR;
- }
- returnOutputBuffers(states.useHalBufManager, /*listener*/nullptr,
- streamBuffers.data(), numAllocatedBuffers, /*timestamp*/0,
- /*readoutTimestamp*/0, /*requested*/false,
- /*requestTimeNs*/0, states.sessionStatsBuilder);
- for (auto buf : newBuffers) {
- states.bufferRecordsIntf.removeOneBufferCache(streamId, buf);
- }
- }
- }
-
- _hidl_cb(allReqsSucceeds ? BufferRequestStatus::OK :
- oneReqSucceeds ? BufferRequestStatus::FAILED_PARTIAL :
- BufferRequestStatus::FAILED_UNKNOWN,
- bufRets);
- states.reqBufferIntf.endRequestBuffer();
-}
-
-void returnStreamBuffers(ReturnBufferStates& states,
- const hardware::hidl_vec<hardware::camera::device::V3_2::StreamBuffer>& buffers) {
- if (!states.useHalBufManager) {
- ALOGE("%s: Camera %s does not support HAL buffer managerment",
- __FUNCTION__, states.cameraId.string());
- return;
- }
-
- for (const auto& buf : buffers) {
- if (buf.bufferId == BUFFER_ID_NO_BUFFER) {
- ALOGE("%s: cannot return a buffer without bufferId", __FUNCTION__);
- continue;
- }
-
- buffer_handle_t* buffer;
- status_t res = states.bufferRecordsIntf.popInflightRequestBuffer(buf.bufferId, &buffer);
-
- if (res != OK) {
- ALOGE("%s: cannot find in-flight buffer %" PRIu64 " for stream %d",
- __FUNCTION__, buf.bufferId, buf.streamId);
- continue;
- }
-
- camera_stream_buffer_t streamBuffer;
- streamBuffer.buffer = buffer;
- streamBuffer.status = CAMERA_BUFFER_STATUS_ERROR;
- streamBuffer.acquire_fence = -1;
- streamBuffer.release_fence = -1;
-
- if (buf.releaseFence == nullptr) {
- streamBuffer.release_fence = -1;
- } else if (buf.releaseFence->numFds == 1) {
- streamBuffer.release_fence = dup(buf.releaseFence->data[0]);
- } else {
- ALOGE("%s: Invalid release fence, fd count is %d, not 1",
- __FUNCTION__, buf.releaseFence->numFds);
- continue;
- }
-
- sp<Camera3StreamInterface> stream = states.outputStreams.get(buf.streamId);
- if (stream == nullptr) {
- ALOGE("%s: Output stream id %d not found!", __FUNCTION__, buf.streamId);
- continue;
- }
- streamBuffer.stream = stream->asHalStream();
- returnOutputBuffers(states.useHalBufManager, /*listener*/nullptr,
- &streamBuffer, /*size*/1, /*timestamp*/ 0, /*readoutTimestamp*/0,
- /*requested*/false, /*requestTimeNs*/0, states.sessionStatsBuilder);
- }
-}
-
void flushInflightRequests(FlushInflightReqStates& states) {
ATRACE_CALL();
{ // First return buffers cached in inFlightMap
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.h b/services/camera/libcameraservice/device3/Camera3OutputUtils.h
index 51899ee..4d1eb75 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputUtils.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.h
@@ -40,8 +40,6 @@
namespace android {
-using ResultMetadataQueue = hardware::MessageQueue<uint8_t, hardware::kSynchronizedReadWrite>;
-
namespace camera3 {
/**
@@ -97,7 +95,6 @@
const metadata_vendor_id_t vendorTagId;
const CameraMetadata& deviceInfo;
const std::unordered_map<std::string, CameraMetadata>& physicalDeviceInfoMap;
- std::unique_ptr<ResultMetadataQueue>& fmq;
std::unordered_map<std::string, camera3::DistortionMapper>& distortionMappers;
std::unordered_map<std::string, camera3::ZoomRatioMapper>& zoomRatioMappers;
std::unordered_map<std::string, camera3::RotateAndCropMapper>& rotateAndCropMappers;
@@ -112,20 +109,8 @@
bool legacyClient;
};
- // Handle one capture result. Assume callers hold the lock to serialize all
- // processCaptureResult calls
- void processOneCaptureResultLocked(
- CaptureOutputStates& states,
- const hardware::camera::device::V3_2::CaptureResult& result,
- const hardware::hidl_vec<
- hardware::camera::device::V3_4::PhysicalCameraMetadata> physicalCameraMetadata);
-
- // Handle one notify message
- void notify(CaptureOutputStates& states,
- const hardware::camera::device::V3_2::NotifyMsg& msg,
- bool hasReadoutTime = false, uint64_t readoutTime = 0LL);
- void notify(CaptureOutputStates& states,
- const hardware::camera::device::V3_8::NotifyMsg& msg);
+ void processCaptureResult(CaptureOutputStates& states, const camera_capture_result *result);
+ void notify(CaptureOutputStates& states, const camera_notify_msg *msg);
struct RequestBufferStates {
const String8& cameraId;
@@ -138,10 +123,6 @@
RequestBufferInterface& reqBufferIntf;
};
- void requestStreamBuffers(RequestBufferStates& states,
- const hardware::hidl_vec<hardware::camera::device::V3_5::BufferRequest>& bufReqs,
- hardware::camera::device::V3_5::ICameraDeviceCallback::requestStreamBuffers_cb _hidl_cb);
-
struct ReturnBufferStates {
const String8& cameraId;
const bool useHalBufManager;
@@ -150,9 +131,6 @@
BufferRecordsInterface& bufferRecordsIntf;
};
- void returnStreamBuffers(ReturnBufferStates& states,
- const hardware::hidl_vec<hardware::camera::device::V3_2::StreamBuffer>& buffers);
-
struct FlushInflightReqStates {
const String8& cameraId;
std::mutex& inflightLock;
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtilsTemplated.h b/services/camera/libcameraservice/device3/Camera3OutputUtilsTemplated.h
new file mode 100644
index 0000000..7dc8e10
--- /dev/null
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtilsTemplated.h
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2022 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_SERVERS_CAMERA3_OUTPUT_TEMPLUTILS_H
+#define ANDROID_SERVERS_CAMERA3_OUTPUT_TEMPLUTILS_H
+
+#include <inttypes.h>
+
+#include <utils/Log.h>
+#include <utils/SortedVector.h>
+#include <utils/Trace.h>
+
+#include <aidl/android/hardware/common/NativeHandle.h>
+#include <android/hardware/camera2/ICameraDeviceCallbacks.h>
+
+#include <android/hardware/camera/device/3.4/ICameraDeviceCallback.h>
+#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
+#include <android/hardware/camera/device/3.5/ICameraDeviceSession.h>
+
+#include <camera/CameraUtils.h>
+#include <camera_metadata_hidden.h>
+
+#include "device3/Camera3OutputUtils.h"
+
+#include "system/camera_metadata.h"
+
+using namespace android::camera3;
+using namespace android::hardware::camera;
+
+namespace android {
+namespace camera3 {
+
+template <class BufferStatusType>
+camera_buffer_status_t mapBufferStatus(BufferStatusType status) {
+ switch (status) {
+ case BufferStatusType::OK: return CAMERA_BUFFER_STATUS_OK;
+ case BufferStatusType::ERROR: return CAMERA_BUFFER_STATUS_ERROR;
+ }
+ return CAMERA_BUFFER_STATUS_ERROR;
+}
+
+inline void readBufferFromVec(hardware::hidl_vec<uint8_t> &dst,
+ const hardware::hidl_vec<uint8_t> &src) {
+ // Not cloning here since that will be done in processCaptureResult whil
+ // assigning to CameraMetadata.
+ dst.setToExternal(const_cast<uint8_t *>(src.data()), src.size());
+}
+
+inline void readBufferFromVec(std::vector<uint8_t> &dst, const std::vector<uint8_t> &src) {
+ // TODO: Check if we're really supposed to copy
+ dst = src;
+}
+// Reading one camera metadata from result argument via fmq or from the result
+// Assuming the fmq is protected by a lock already
+template <class FmqType, class MetadataType>
+status_t readOneCameraMetadataLockedT(
+ std::unique_ptr<FmqType>& fmq,
+ uint64_t fmqResultSize,
+ MetadataType& resultMetadata,
+ const MetadataType& result) {
+ if (fmqResultSize > 0) {
+ resultMetadata.resize(fmqResultSize);
+ if (fmq == nullptr) {
+ return NO_MEMORY; // logged in initialize()
+ }
+ if (!fmq->read(resultMetadata.data(), fmqResultSize)) {
+ ALOGE("%s: Cannot read camera metadata from fmq, size = %" PRIu64,
+ __FUNCTION__, fmqResultSize);
+ return INVALID_OPERATION;
+ }
+ } else {
+ readBufferFromVec(resultMetadata, result);
+ }
+
+ if (resultMetadata.size() != 0) {
+ status_t res;
+ const camera_metadata_t* metadata =
+ reinterpret_cast<const camera_metadata_t*>(resultMetadata.data());
+ size_t expected_metadata_size = resultMetadata.size();
+ if ((res = validate_camera_metadata_structure(metadata, &expected_metadata_size)) != OK) {
+ ALOGE("%s: Invalid camera metadata received by camera service from HAL: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return INVALID_OPERATION;
+ }
+ }
+
+ return OK;
+}
+
+inline bool isHandleNull(const hardware::hidl_handle &handle) {
+ return handle == nullptr;
+}
+
+inline bool isHandleNull(const aidl::android::hardware::common::NativeHandle &handle) {
+ return (handle.fds.size() == 0) && (handle.ints.size() == 0);
+}
+
+inline size_t numFdsInHandle(const hardware::hidl_handle &handle) {
+ return handle->numFds;
+}
+
+inline size_t numFdsInHandle(const aidl::android::hardware::common::NativeHandle &handle) {
+ return handle.fds.size();
+}
+
+inline int32_t getHandleFirstFd(const hardware::hidl_handle &handle) {
+ if (handle->numFds != 1) {
+ return -1;
+ }
+ return handle->data[0];
+}
+
+inline int32_t getHandleFirstFd(const aidl::android::hardware::common::NativeHandle &handle) {
+ if (handle.fds.size() != 1) {
+ return -1;
+ }
+ return handle.fds[0].get();
+}
+
+template <class StatesType, class CaptureResultType, class PhysMetadataType, class MetadataType,
+ class FmqType, class BufferStatusType>
+void processOneCaptureResultLockedT(
+ StatesType& states,
+ const CaptureResultType& result,
+ const PhysMetadataType &physicalCameraMetadata) {
+ std::unique_ptr<FmqType>& fmq = states.fmq;
+ BufferRecordsInterface& bufferRecords = states.bufferRecordsIntf;
+ camera_capture_result r;
+ status_t res;
+ r.frame_number = result.frameNumber;
+
+ // Read and validate the result metadata.
+ MetadataType resultMetadata;
+ res = readOneCameraMetadataLockedT(
+ fmq, result.fmqResultSize,
+ resultMetadata, result.result);
+ if (res != OK) {
+ ALOGE("%s: Frame %d: Failed to read capture result metadata",
+ __FUNCTION__, result.frameNumber);
+ return;
+ }
+ r.result = reinterpret_cast<const camera_metadata_t*>(resultMetadata.data());
+
+ // Read and validate physical camera metadata
+ size_t physResultCount = physicalCameraMetadata.size();
+ std::vector<const char*> physCamIds(physResultCount);
+ std::vector<const camera_metadata_t *> phyCamMetadatas(physResultCount);
+ std::vector<MetadataType> physResultMetadata;
+ physResultMetadata.resize(physResultCount);
+ for (size_t i = 0; i < physicalCameraMetadata.size(); i++) {
+ res = readOneCameraMetadataLockedT(fmq, physicalCameraMetadata[i].fmqMetadataSize,
+ physResultMetadata[i], physicalCameraMetadata[i].metadata);
+ if (res != OK) {
+ ALOGE("%s: Frame %d: Failed to read capture result metadata for camera %s",
+ __FUNCTION__, result.frameNumber,
+ physicalCameraMetadata[i].physicalCameraId.c_str());
+ return;
+ }
+ physCamIds[i] = physicalCameraMetadata[i].physicalCameraId.c_str();
+ phyCamMetadatas[i] = reinterpret_cast<const camera_metadata_t*>(
+ physResultMetadata[i].data());
+ }
+ r.num_physcam_metadata = physResultCount;
+ r.physcam_ids = physCamIds.data();
+ r.physcam_metadata = phyCamMetadatas.data();
+
+ std::vector<camera_stream_buffer_t> outputBuffers(result.outputBuffers.size());
+ std::vector<buffer_handle_t> outputBufferHandles(result.outputBuffers.size());
+ for (size_t i = 0; i < result.outputBuffers.size(); i++) {
+ auto& bDst = outputBuffers[i];
+ const auto &bSrc = result.outputBuffers[i];
+
+ sp<Camera3StreamInterface> stream = states.outputStreams.get(bSrc.streamId);
+ if (stream == nullptr) {
+ ALOGE("%s: Frame %d: Buffer %zu: Invalid output stream id %d",
+ __FUNCTION__, result.frameNumber, i, bSrc.streamId);
+ return;
+ }
+ bDst.stream = stream->asHalStream();
+
+ bool noBufferReturned = false;
+ buffer_handle_t *buffer = nullptr;
+ if (states.useHalBufManager) {
+ // This is suspicious most of the time but can be correct during flush where HAL
+ // has to return capture result before a buffer is requested
+ if (bSrc.bufferId == BUFFER_ID_NO_BUFFER) {
+ if (bSrc.status == BufferStatusType::OK) {
+ ALOGE("%s: Frame %d: Buffer %zu: No bufferId for stream %d",
+ __FUNCTION__, result.frameNumber, i, bSrc.streamId);
+ // Still proceeds so other buffers can be returned
+ }
+ noBufferReturned = true;
+ }
+ if (noBufferReturned) {
+ res = OK;
+ } else {
+ res = bufferRecords.popInflightRequestBuffer(bSrc.bufferId, &buffer);
+ }
+ } else {
+ res = bufferRecords.popInflightBuffer(result.frameNumber, bSrc.streamId, &buffer);
+ }
+
+ if (res != OK) {
+ ALOGE("%s: Frame %d: Buffer %zu: No in-flight buffer for stream %d",
+ __FUNCTION__, result.frameNumber, i, bSrc.streamId);
+ return;
+ }
+
+ bDst.buffer = buffer;
+ bDst.status = mapBufferStatus<BufferStatusType>(bSrc.status);
+ bDst.acquire_fence = -1;
+ if (isHandleNull(bSrc.releaseFence)) {
+ bDst.release_fence = -1;
+ } else if (numFdsInHandle(bSrc.releaseFence) == 1) {
+ if (noBufferReturned) {
+ ALOGE("%s: got releaseFence without output buffer!", __FUNCTION__);
+ }
+ bDst.release_fence = dup(getHandleFirstFd(bSrc.releaseFence));
+ } else {
+ ALOGE("%s: Frame %d: Invalid release fence for buffer %zu, fd count is %d, not 1",
+ __FUNCTION__, result.frameNumber, i, (int)numFdsInHandle(bSrc.releaseFence));
+ return;
+ }
+ }
+ r.num_output_buffers = outputBuffers.size();
+ r.output_buffers = outputBuffers.data();
+
+ camera_stream_buffer_t inputBuffer;
+ if (result.inputBuffer.streamId == -1) {
+ r.input_buffer = nullptr;
+ } else {
+ if (states.inputStream->getId() != result.inputBuffer.streamId) {
+ ALOGE("%s: Frame %d: Invalid input stream id %d", __FUNCTION__,
+ result.frameNumber, result.inputBuffer.streamId);
+ return;
+ }
+ inputBuffer.stream = states.inputStream->asHalStream();
+ buffer_handle_t *buffer;
+ res = bufferRecords.popInflightBuffer(result.frameNumber, result.inputBuffer.streamId,
+ &buffer);
+ if (res != OK) {
+ ALOGE("%s: Frame %d: Input buffer: No in-flight buffer for stream %d",
+ __FUNCTION__, result.frameNumber, result.inputBuffer.streamId);
+ return;
+ }
+ inputBuffer.buffer = buffer;
+ inputBuffer.status = mapBufferStatus<BufferStatusType>(result.inputBuffer.status);
+ inputBuffer.acquire_fence = -1;
+ if (isHandleNull(result.inputBuffer.releaseFence)) {
+ inputBuffer.release_fence = -1;
+ } else if (numFdsInHandle(result.inputBuffer.releaseFence) == 1) {
+ inputBuffer.release_fence = dup(getHandleFirstFd(result.inputBuffer.releaseFence));
+ } else {
+ ALOGE("%s: Frame %d: Invalid release fence for input buffer, fd count is %d, not 1",
+ __FUNCTION__, result.frameNumber,
+ (int)numFdsInHandle(result.inputBuffer.releaseFence));
+ return;
+ }
+ r.input_buffer = &inputBuffer;
+ }
+
+ r.partial_result = result.partialResult;
+
+ processCaptureResult(states, &r);
+}
+
+template <class VecStreamBufferType>
+void returnStreamBuffersT(ReturnBufferStates& states,
+ const VecStreamBufferType& buffers) {
+ if (!states.useHalBufManager) {
+ ALOGE("%s: Camera %s does not support HAL buffer managerment",
+ __FUNCTION__, states.cameraId.string());
+ return;
+ }
+
+ for (const auto& buf : buffers) {
+ if (buf.bufferId == BUFFER_ID_NO_BUFFER) {
+ ALOGE("%s: cannot return a buffer without bufferId", __FUNCTION__);
+ continue;
+ }
+
+ buffer_handle_t* buffer;
+ status_t res = states.bufferRecordsIntf.popInflightRequestBuffer(buf.bufferId, &buffer);
+
+ if (res != OK) {
+ ALOGE("%s: cannot find in-flight buffer %" PRIu64 " for stream %d",
+ __FUNCTION__, buf.bufferId, buf.streamId);
+ continue;
+ }
+
+ camera_stream_buffer_t streamBuffer;
+ streamBuffer.buffer = buffer;
+ streamBuffer.status = CAMERA_BUFFER_STATUS_ERROR;
+ streamBuffer.acquire_fence = -1;
+ streamBuffer.release_fence = -1;
+
+ if (isHandleNull(buf.releaseFence)) {
+ streamBuffer.release_fence = -1;
+ } else if (numFdsInHandle(buf.releaseFence) == 1) {
+ streamBuffer.release_fence = dup(getHandleFirstFd(buf.releaseFence));
+ } else {
+ ALOGE("%s: Invalid release fence, fd count is %d, not 1",
+ __FUNCTION__, (int)numFdsInHandle(buf.releaseFence));
+ continue;
+ }
+
+ sp<Camera3StreamInterface> stream = states.outputStreams.get(buf.streamId);
+ if (stream == nullptr) {
+ ALOGE("%s: Output stream id %d not found!", __FUNCTION__, buf.streamId);
+ continue;
+ }
+ streamBuffer.stream = stream->asHalStream();
+ returnOutputBuffers(states.useHalBufManager, /*listener*/nullptr,
+ &streamBuffer, /*size*/1, /*timestamp*/ 0, /*readoutTimestamp*/0,
+ /*requested*/false, /*requestTimeNs*/0, states.sessionStatsBuilder);
+ }
+}
+
+} // camera3
+} // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
index 9e0c8f3..0e2671a 100644
--- a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
@@ -33,10 +33,10 @@
camera_stream_rotation_t rotation,
nsecs_t timestampOffset, const String8& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
- int setId, bool useHalBufManager) :
+ int setId, bool useHalBufManager, int dynamicProfile) :
Camera3OutputStream(id, CAMERA_STREAM_OUTPUT, width, height,
format, dataSpace, rotation, physicalCameraId, sensorPixelModesUsed,
- consumerUsage, timestampOffset, setId),
+ consumerUsage, timestampOffset, setId, dynamicProfile),
mUseHalBufManager(useHalBufManager) {
size_t consumerCount = std::min(surfaces.size(), kMaxOutputs);
if (surfaces.size() > consumerCount) {
@@ -67,7 +67,7 @@
}
res = mStreamSplitter->connect(initialSurfaces, usage, mUsage, camera_stream::max_buffers,
- getWidth(), getHeight(), getFormat(), &mConsumer);
+ getWidth(), getHeight(), getFormat(), &mConsumer, camera_stream::dynamic_range_profile);
if (res != OK) {
ALOGE("%s: Failed to connect to stream splitter: %s(%d)",
__FUNCTION__, strerror(-res), res);
@@ -388,13 +388,15 @@
bool sizeMismatch = ((static_cast<uint32_t>(infoIt.width) != getWidth()) ||
(static_cast<uint32_t> (infoIt.height) != getHeight())) ?
true : false;
- if ((imgReaderUsage && sizeMismatch) ||
+ bool dynamicRangeMismatch = dynamic_range_profile != infoIt.dynamicRangeProfile;
+ if ((imgReaderUsage && sizeMismatch) || dynamicRangeMismatch ||
(infoIt.format != getOriginalFormat() && infoIt.format != getFormat()) ||
(infoIt.dataSpace != getDataSpace() &&
infoIt.dataSpace != getOriginalDataSpace())) {
- ALOGE("%s: Shared surface parameters format: 0x%x dataSpace: 0x%x "
- " don't match source stream format: 0x%x dataSpace: 0x%x", __FUNCTION__,
- infoIt.format, infoIt.dataSpace, getFormat(), getDataSpace());
+ ALOGE("%s: Shared surface parameters format: 0x%x dataSpace: 0x%x dynamic range 0x%x "
+ " don't match source stream format: 0x%x dataSpace: 0x%x dynamic range 0x%x"
+ , __FUNCTION__, infoIt.format, infoIt.dataSpace, infoIt.dynamicRangeProfile,
+ getFormat(), getDataSpace(), dynamic_range_profile);
return BAD_VALUE;
}
}
diff --git a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
index 4b6341b..fafa26f 100644
--- a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
@@ -40,7 +40,8 @@
const String8& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
int setId = CAMERA3_STREAM_SET_ID_INVALID,
- bool useHalBufManager = false);
+ bool useHalBufManager = false,
+ int dynamicProfile = ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD);
virtual ~Camera3SharedOutputStream();
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 1405fa1..83f9a98 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <vector>
+#include "system/window.h"
#define LOG_TAG "Camera3-Stream"
#define ATRACE_TAG ATRACE_TAG_CAMERA
//#define LOG_NDEBUG 0
@@ -23,6 +25,7 @@
#include "device3/Camera3Stream.h"
#include "device3/StatusTracker.h"
#include "utils/TraceHFR.h"
+#include "ui/GraphicBufferMapper.h"
#include <cutils/properties.h>
@@ -51,7 +54,7 @@
android_dataspace dataSpace, camera_stream_rotation_t rotation,
const String8& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
- int setId, bool isMultiResolution) :
+ int setId, bool isMultiResolution, int dynamicRangeProfile) :
camera_stream(),
mId(id),
mSetId(setId),
@@ -87,6 +90,7 @@
camera_stream::max_buffers = 0;
camera_stream::physical_camera_id = mPhysicalCameraId.string();
camera_stream::sensor_pixel_modes_used = sensorPixelModesUsed;
+ camera_stream::dynamic_range_profile = dynamicRangeProfile;
if ((format == HAL_PIXEL_FORMAT_BLOB || format == HAL_PIXEL_FORMAT_RAW_OPAQUE) &&
maxSize == 0) {
@@ -147,6 +151,10 @@
return mOriginalFormat;
}
+int Camera3Stream::getDynamicRangeProfile() const {
+ return camera_stream::dynamic_range_profile;
+}
+
void Camera3Stream::setDataSpaceOverride(bool dataSpaceOverridden) {
mDataSpaceOverridden = dataSpaceOverridden;
}
@@ -1078,6 +1086,52 @@
return res;
}
+void Camera3Stream::queueHDRMetadata(buffer_handle_t buffer, sp<ANativeWindow>& anw,
+ int dynamicRangeProfile) {
+ auto& mapper = GraphicBufferMapper::get();
+ switch (dynamicRangeProfile) {
+ case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10: {
+ std::optional<ui::Smpte2086> smpte2086;
+ auto res = mapper.getSmpte2086(buffer, &smpte2086);
+ if ((res == OK) && smpte2086.has_value()) {
+ const auto& metaValue = smpte2086.value();
+ android_smpte2086_metadata meta = {
+ .displayPrimaryRed.x = metaValue.primaryRed.x,
+ .displayPrimaryRed.y = metaValue.primaryRed.y,
+ .displayPrimaryGreen.x = metaValue.primaryGreen.x,
+ .displayPrimaryGreen.y = metaValue.primaryGreen.y,
+ .displayPrimaryBlue.x = metaValue.primaryBlue.x,
+ .displayPrimaryBlue.y = metaValue.primaryBlue.y,
+ .whitePoint.x = metaValue.whitePoint.x,
+ .whitePoint.y = metaValue.whitePoint.y,
+ .maxLuminance = metaValue.maxLuminance,
+ .minLuminance = metaValue.minLuminance};
+ native_window_set_buffers_smpte2086_metadata(anw.get(), &meta);
+ } else {
+ ALOGE("%s Couldn't retrieve Smpte2086 metadata %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ }
+ break;
+ }
+ case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10_PLUS: {
+ std::optional<std::vector<uint8_t>> smpte2094_40;
+ auto res = mapper.getSmpte2094_40(buffer, &smpte2094_40);
+ if ((res == OK) && smpte2094_40.has_value()) {
+ native_window_set_buffers_hdr10_plus_metadata(anw.get(),
+ smpte2094_40.value().size(), smpte2094_40.value().data());
+ } else {
+ ALOGE("%s Couldn't retrieve Smpte2094_40 metadata %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ }
+ break;
+ }
+ default:
+ // No-op
+ break;
+ }
+}
+
+
}; // namespace camera3
}; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index 17041de..bbbea8d 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -138,6 +138,10 @@
static Camera3Stream* cast(camera_stream *stream);
static const Camera3Stream* cast(const camera_stream *stream);
+ // Queue corresponding HDR metadata to given native window.
+ static void queueHDRMetadata(buffer_handle_t buffer, sp<ANativeWindow>& anw,
+ int dynamicRangeProfile);
+
/**
* Get the stream's ID
*/
@@ -168,6 +172,7 @@
void setFormatOverride(bool formatOverriden);
bool isFormatOverridden() const;
int getOriginalFormat() const;
+ int getDynamicRangeProfile() const;
void setDataSpaceOverride(bool dataSpaceOverriden);
bool isDataSpaceOverridden() const;
android_dataspace getOriginalDataSpace() const;
@@ -500,7 +505,7 @@
android_dataspace dataSpace, camera_stream_rotation_t rotation,
const String8& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
- int setId, bool isMultiResolution);
+ int setId, bool isMultiResolution, int dynamicRangeProfile);
wp<Camera3StreamBufferFreedListener> mBufferFreedListener;
diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
index 5f20f17..ef10f0d 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
@@ -64,6 +64,7 @@
const char* physical_camera_id;
std::unordered_set<int32_t> sensor_pixel_modes_used;
+ int dynamic_range_profile;
} camera_stream_t;
typedef struct camera_stream_buffer {
@@ -107,14 +108,17 @@
bool finalized = false;
bool supportsOffline = false;
std::unordered_set<int32_t> sensorPixelModesUsed;
+ int dynamicRangeProfile;
OutputStreamInfo() :
width(-1), height(-1), format(-1), dataSpace(HAL_DATASPACE_UNKNOWN),
- consumerUsage(0) {}
+ consumerUsage(0),
+ dynamicRangeProfile(ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD) {}
OutputStreamInfo(int _width, int _height, int _format, android_dataspace _dataSpace,
- uint64_t _consumerUsage, const std::unordered_set<int32_t>& _sensorPixelModesUsed) :
+ uint64_t _consumerUsage, const std::unordered_set<int32_t>& _sensorPixelModesUsed,
+ int _dynamicRangeProfile) :
width(_width), height(_height), format(_format),
dataSpace(_dataSpace), consumerUsage(_consumerUsage),
- sensorPixelModesUsed(_sensorPixelModesUsed) {}
+ sensorPixelModesUsed(_sensorPixelModesUsed), dynamicRangeProfile(_dynamicRangeProfile){}
};
/**
@@ -154,6 +158,7 @@
virtual uint32_t getWidth() const = 0;
virtual uint32_t getHeight() const = 0;
virtual int getFormat() const = 0;
+ virtual int getDynamicRangeProfile() const = 0;
virtual android_dataspace getDataSpace() const = 0;
virtual void setFormatOverride(bool formatOverriden) = 0;
virtual bool isFormatOverridden() const = 0;
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
index 5c6c518..1149d13 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
@@ -34,13 +34,16 @@
#include <cutils/atomic.h>
+#include "Camera3Stream.h"
+
#include "Camera3StreamSplitter.h"
namespace android {
status_t Camera3StreamSplitter::connect(const std::unordered_map<size_t, sp<Surface>> &surfaces,
uint64_t consumerUsage, uint64_t producerUsage, size_t halMaxBuffers, uint32_t width,
- uint32_t height, android::PixelFormat format, sp<Surface>* consumer) {
+ uint32_t height, android::PixelFormat format, sp<Surface>* consumer,
+ int dynamicRangeProfile) {
ATRACE_CALL();
if (consumer == nullptr) {
SP_LOGE("%s: consumer pointer is NULL", __FUNCTION__);
@@ -61,6 +64,7 @@
mMaxHalBuffers = halMaxBuffers;
mConsumerName = getUniqueConsumerName();
+ mDynamicRangeProfile = dynamicRangeProfile;
// Add output surfaces. This has to be before creating internal buffer queue
// in order to get max consumer side buffers.
for (auto &it : surfaces) {
@@ -136,6 +140,7 @@
}
}
mOutputs.clear();
+ mOutputSurfaces.clear();
mOutputSlots.clear();
mConsumerBufferCount.clear();
@@ -258,6 +263,7 @@
// Add new entry into mOutputs
mOutputs[surfaceId] = gbp;
+ mOutputSurfaces[surfaceId] = outputQueue;
mConsumerBufferCount[surfaceId] = maxConsumerBuffers;
if (mConsumerBufferCount[surfaceId] > mMaxHalBuffers) {
SP_LOGW("%s: Consumer buffer count %zu larger than max. Hal buffers: %zu", __FUNCTION__,
@@ -316,6 +322,7 @@
}
}
mOutputs[surfaceId] = nullptr;
+ mOutputSurfaces[surfaceId] = nullptr;
mOutputSlots[gbp] = nullptr;
for (const auto &id : pendingBufferIds) {
decrementBufRefCountLocked(id, surfaceId);
@@ -356,6 +363,14 @@
const BufferTracker& tracker = *(mBuffers[bufferId]);
int slot = getSlotForOutputLocked(output, tracker.getBuffer());
+ if (mOutputSurfaces[surfaceId] != nullptr) {
+ sp<ANativeWindow> anw = mOutputSurfaces[surfaceId];
+ camera3::Camera3Stream::queueHDRMetadata(
+ bufferItem.mGraphicBuffer->getNativeBuffer()->handle, anw, mDynamicRangeProfile);
+ } else {
+ SP_LOGE("%s: Invalid surface id: %zu!", __FUNCTION__, surfaceId);
+ }
+
// In case the output BufferQueue has its own lock, if we hold splitter lock while calling
// queueBuffer (which will try to acquire the output lock), the output could be holding its
// own lock calling releaseBuffer (which will try to acquire the splitter lock), running into
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.h b/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
index 4eb455a..827865c 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
@@ -19,6 +19,8 @@
#include <unordered_set>
+#include <camera/CameraMetadata.h>
+
#include <gui/IConsumerListener.h>
#include <gui/IProducerListener.h>
#include <gui/BufferItemConsumer.h>
@@ -55,7 +57,8 @@
// with output surfaces.
status_t connect(const std::unordered_map<size_t, sp<Surface>> &surfaces,
uint64_t consumerUsage, uint64_t producerUsage, size_t halMaxBuffers, uint32_t width,
- uint32_t height, android::PixelFormat format, sp<Surface>* consumer);
+ uint32_t height, android::PixelFormat format, sp<Surface>* consumer,
+ int dynamicRangeProfile);
// addOutput adds an output BufferQueue to the splitter. The splitter
// connects to outputQueue as a CPU producer, and any buffers queued
@@ -232,6 +235,7 @@
uint32_t mHeight = 0;
android::PixelFormat mFormat = android::PIXEL_FORMAT_NONE;
uint64_t mProducerUsage = 0;
+ int mDynamicRangeProfile = ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD;
// The attachBuffer call will happen on different thread according to mUseHalBufManager and have
// different timing constraint.
@@ -251,6 +255,9 @@
//Map surface ids -> gbp outputs
std::unordered_map<int, sp<IGraphicBufferProducer> > mOutputs;
+ //Map surface ids -> gbp outputs
+ std::unordered_map<int, sp<Surface>> mOutputSurfaces;
+
//Map surface ids -> consumer buffer count
std::unordered_map<int, size_t > mConsumerBufferCount;
diff --git a/services/camera/libcameraservice/device3/DistortionMapper.cpp b/services/camera/libcameraservice/device3/DistortionMapper.cpp
index 89dd115..15807bf 100644
--- a/services/camera/libcameraservice/device3/DistortionMapper.cpp
+++ b/services/camera/libcameraservice/device3/DistortionMapper.cpp
@@ -22,7 +22,7 @@
#include <cmath>
#include "device3/DistortionMapper.h"
-#include "utils/SessionConfigurationUtils.h"
+#include "utils/SessionConfigurationUtilsHost.h"
namespace android {
diff --git a/services/camera/libcameraservice/device3/PreviewFrameScheduler.cpp b/services/camera/libcameraservice/device3/PreviewFrameScheduler.cpp
index 1fbdb18..6135f9e 100644
--- a/services/camera/libcameraservice/device3/PreviewFrameScheduler.cpp
+++ b/services/camera/libcameraservice/device3/PreviewFrameScheduler.cpp
@@ -44,7 +44,7 @@
size_t length = AChoreographerFrameCallbackData_getFrameTimelinesLength(callbackData);
std::vector<nsecs_t> timeline(length);
for (size_t i = 0; i < length; i++) {
- nsecs_t timestamp = AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTime(
+ nsecs_t timestamp = AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTimeNanos(
callbackData, i);
timeline[i] = timestamp;
}
@@ -196,6 +196,9 @@
return res;
}
+ Camera3Stream::queueHDRMetadata(bufferHolder.anwBuffer.get()->handle, mConsumer,
+ mParent.getDynamicRangeProfile());
+
res = mConsumer->queueBuffer(mConsumer.get(), bufferHolder.anwBuffer.get(),
bufferHolder.releaseFence);
if (res != OK) {
diff --git a/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp b/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp
index 7ec0956..27b00c9 100644
--- a/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp
+++ b/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp
@@ -20,7 +20,7 @@
#include <algorithm>
#include "device3/ZoomRatioMapper.h"
-#include "utils/SessionConfigurationUtils.h"
+#include "utils/SessionConfigurationUtilsHost.h"
namespace android {
diff --git a/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp
new file mode 100644
index 0000000..7b7a2a2
--- /dev/null
+++ b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp
@@ -0,0 +1,1893 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "HidlCamera3-Device"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+//#define LOG_NNDEBUG 0 // Per-frame verbose logging
+
+#ifdef LOG_NNDEBUG
+#define ALOGVV(...) ALOGV(__VA_ARGS__)
+#else
+#define ALOGVV(...) ((void)0)
+#endif
+
+// Convenience macro for transient errors
+#define CLOGE(fmt, ...) ALOGE("Camera %s: %s: " fmt, mId.string(), __FUNCTION__, \
+ ##__VA_ARGS__)
+
+// Convenience macros for transitioning to the error state
+#define SET_ERR(fmt, ...) setErrorState( \
+ "%s: " fmt, __FUNCTION__, \
+ ##__VA_ARGS__)
+#define SET_ERR_L(fmt, ...) setErrorStateLocked( \
+ "%s: " fmt, __FUNCTION__, \
+ ##__VA_ARGS__)
+
+
+#include <inttypes.h>
+
+#include <utility>
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+#include <utils/Timers.h>
+#include <cutils/properties.h>
+
+#include <android/hardware/camera/device/3.7/ICameraInjectionSession.h>
+#include <android/hardware/camera2/ICameraDeviceUser.h>
+
+#include "device3/hidl/HidlCamera3OutputUtils.h"
+#include "device3/hidl/HidlCamera3OfflineSession.h"
+#include "utils/SessionConfigurationUtils.h"
+#include "utils/TraceHFR.h"
+
+#include "../../common/hidl/HidlProviderInfo.h"
+#include "HidlCamera3Device.h"
+
+#include <algorithm>
+#include <tuple>
+
+using namespace android::camera3;
+using namespace android::hardware::camera;
+using namespace android::hardware::camera::device::V3_2;
+using android::hardware::camera::metadata::V3_6::CameraMetadataEnumAndroidSensorPixelMode;
+
+namespace android {
+
+CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap
+HidlCamera3Device::mapToHidlDynamicProfile(int dynamicRangeProfile) {
+ return static_cast<CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap>(
+ dynamicRangeProfile);
+}
+
+hardware::graphics::common::V1_0::PixelFormat HidlCamera3Device::mapToPixelFormat(
+ int frameworkFormat) {
+ return (hardware::graphics::common::V1_0::PixelFormat) frameworkFormat;
+}
+
+DataspaceFlags HidlCamera3Device::mapToHidlDataspace(
+ android_dataspace dataSpace) {
+ return dataSpace;
+}
+
+BufferUsageFlags HidlCamera3Device::mapToConsumerUsage(
+ uint64_t usage) {
+ return usage;
+}
+
+StreamRotation HidlCamera3Device::mapToStreamRotation(camera_stream_rotation_t rotation) {
+ switch (rotation) {
+ case CAMERA_STREAM_ROTATION_0:
+ return StreamRotation::ROTATION_0;
+ case CAMERA_STREAM_ROTATION_90:
+ return StreamRotation::ROTATION_90;
+ case CAMERA_STREAM_ROTATION_180:
+ return StreamRotation::ROTATION_180;
+ case CAMERA_STREAM_ROTATION_270:
+ return StreamRotation::ROTATION_270;
+ }
+ ALOGE("%s: Unknown stream rotation %d", __FUNCTION__, rotation);
+ return StreamRotation::ROTATION_0;
+}
+
+status_t HidlCamera3Device::mapToStreamConfigurationMode(
+ camera_stream_configuration_mode_t operationMode, StreamConfigurationMode *mode) {
+ if (mode == nullptr) return BAD_VALUE;
+ if (operationMode < CAMERA_VENDOR_STREAM_CONFIGURATION_MODE_START) {
+ switch(operationMode) {
+ case CAMERA_STREAM_CONFIGURATION_NORMAL_MODE:
+ *mode = StreamConfigurationMode::NORMAL_MODE;
+ break;
+ case CAMERA_STREAM_CONFIGURATION_CONSTRAINED_HIGH_SPEED_MODE:
+ *mode = StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE;
+ break;
+ default:
+ ALOGE("%s: Unknown stream configuration mode %d", __FUNCTION__, operationMode);
+ return BAD_VALUE;
+ }
+ } else {
+ *mode = static_cast<StreamConfigurationMode>(operationMode);
+ }
+ return OK;
+}
+
+int HidlCamera3Device::mapToFrameworkFormat(
+ hardware::graphics::common::V1_0::PixelFormat pixelFormat) {
+ return static_cast<uint32_t>(pixelFormat);
+}
+
+android_dataspace HidlCamera3Device::mapToFrameworkDataspace(
+ DataspaceFlags dataSpace) {
+ return static_cast<android_dataspace>(dataSpace);
+}
+
+uint64_t HidlCamera3Device::mapConsumerToFrameworkUsage(
+ BufferUsageFlags usage) {
+ return usage;
+}
+
+uint64_t HidlCamera3Device::mapProducerToFrameworkUsage(
+ BufferUsageFlags usage) {
+ return usage;
+}
+
+status_t HidlCamera3Device::initialize(sp<CameraProviderManager> manager,
+ const String8& monitorTags) {
+ ATRACE_CALL();
+ Mutex::Autolock il(mInterfaceLock);
+ Mutex::Autolock l(mLock);
+
+ ALOGV("%s: Initializing HIDL device for camera %s", __FUNCTION__, mId.string());
+ if (mStatus != STATUS_UNINITIALIZED) {
+ CLOGE("Already initialized!");
+ return INVALID_OPERATION;
+ }
+ if (manager == nullptr) return INVALID_OPERATION;
+
+ sp<ICameraDeviceSession> session;
+ ATRACE_BEGIN("CameraHal::openSession");
+ status_t res = manager->openHidlSession(mId.string(), this,
+ /*out*/ &session);
+ ATRACE_END();
+ if (res != OK) {
+ SET_ERR_L("Could not open camera session: %s (%d)", strerror(-res), res);
+ return res;
+ }
+
+ res = manager->getCameraCharacteristics(mId.string(), mOverrideForPerfClass, &mDeviceInfo);
+ if (res != OK) {
+ SET_ERR_L("Could not retrieve camera characteristics: %s (%d)", strerror(-res), res);
+ session->close();
+ return res;
+ }
+ mSupportNativeZoomRatio = manager->supportNativeZoomRatio(mId.string());
+
+ std::vector<std::string> physicalCameraIds;
+ bool isLogical = manager->isLogicalCamera(mId.string(), &physicalCameraIds);
+ if (isLogical) {
+ for (auto& physicalId : physicalCameraIds) {
+ // Do not override characteristics for physical cameras
+ res = manager->getCameraCharacteristics(
+ physicalId, /*overrideForPerfClass*/false, &mPhysicalDeviceInfoMap[physicalId]);
+ if (res != OK) {
+ SET_ERR_L("Could not retrieve camera %s characteristics: %s (%d)",
+ physicalId.c_str(), strerror(-res), res);
+ session->close();
+ return res;
+ }
+
+ bool usePrecorrectArray =
+ DistortionMapper::isDistortionSupported(mPhysicalDeviceInfoMap[physicalId]);
+ if (usePrecorrectArray) {
+ res = mDistortionMappers[physicalId].setupStaticInfo(
+ mPhysicalDeviceInfoMap[physicalId]);
+ if (res != OK) {
+ SET_ERR_L("Unable to read camera %s's calibration fields for distortion "
+ "correction", physicalId.c_str());
+ session->close();
+ return res;
+ }
+ }
+
+ mZoomRatioMappers[physicalId] = ZoomRatioMapper(
+ &mPhysicalDeviceInfoMap[physicalId],
+ mSupportNativeZoomRatio, usePrecorrectArray);
+
+ if (SessionConfigurationUtils::isUltraHighResolutionSensor(
+ mPhysicalDeviceInfoMap[physicalId])) {
+ mUHRCropAndMeteringRegionMappers[physicalId] =
+ UHRCropAndMeteringRegionMapper(mPhysicalDeviceInfoMap[physicalId],
+ usePrecorrectArray);
+ }
+ }
+ }
+
+ std::shared_ptr<RequestMetadataQueue> queue;
+ auto requestQueueRet = session->getCaptureRequestMetadataQueue(
+ [&queue](const auto& descriptor) {
+ queue = std::make_shared<RequestMetadataQueue>(descriptor);
+ if (!queue->isValid() || queue->availableToWrite() <= 0) {
+ ALOGE("HAL returns empty request metadata fmq, not use it");
+ queue = nullptr;
+ // don't use the queue onwards.
+ }
+ });
+ if (!requestQueueRet.isOk()) {
+ ALOGE("Transaction error when getting request metadata fmq: %s, not use it",
+ requestQueueRet.description().c_str());
+ return DEAD_OBJECT;
+ }
+
+ std::unique_ptr<ResultMetadataQueue>& resQueue = mResultMetadataQueue;
+ auto resultQueueRet = session->getCaptureResultMetadataQueue(
+ [&resQueue](const auto& descriptor) {
+ resQueue = std::make_unique<ResultMetadataQueue>(descriptor);
+ if (!resQueue->isValid() || resQueue->availableToWrite() <= 0) {
+ ALOGE("HAL returns empty result metadata fmq, not use it");
+ resQueue = nullptr;
+ // Don't use the resQueue onwards.
+ }
+ });
+ if (!resultQueueRet.isOk()) {
+ ALOGE("Transaction error when getting result metadata queue from camera session: %s",
+ resultQueueRet.description().c_str());
+ return DEAD_OBJECT;
+ }
+ IF_ALOGV() {
+ session->interfaceChain([](
+ ::android::hardware::hidl_vec<::android::hardware::hidl_string> interfaceChain) {
+ ALOGV("Session interface chain:");
+ for (const auto& iface : interfaceChain) {
+ ALOGV(" %s", iface.c_str());
+ }
+ });
+ }
+
+ camera_metadata_entry bufMgrMode =
+ mDeviceInfo.find(ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION);
+ if (bufMgrMode.count > 0) {
+ mUseHalBufManager = (bufMgrMode.data.u8[0] ==
+ ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5);
+ }
+
+ camera_metadata_entry_t capabilities = mDeviceInfo.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
+ for (size_t i = 0; i < capabilities.count; i++) {
+ uint8_t capability = capabilities.data.u8[i];
+ if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING) {
+ mSupportOfflineProcessing = true;
+ }
+ }
+
+ mInterface = new HidlHalInterface(session, queue, mUseHalBufManager, mSupportOfflineProcessing);
+
+ std::string providerType;
+ mVendorTagId = manager->getProviderTagIdLocked(mId.string());
+ mTagMonitor.initialize(mVendorTagId);
+ if (!monitorTags.isEmpty()) {
+ mTagMonitor.parseTagsToMonitor(String8(monitorTags));
+ }
+
+ // Metadata tags needs fixup for monochrome camera device version less
+ // than 3.5.
+ hardware::hidl_version maxVersion{0,0};
+ res = manager->getHighestSupportedVersion(mId.string(), &maxVersion);
+ if (res != OK) {
+ ALOGE("%s: Error in getting camera device version id: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+ int deviceVersion = HARDWARE_DEVICE_API_VERSION(
+ maxVersion.get_major(), maxVersion.get_minor());
+
+ bool isMonochrome = false;
+ for (size_t i = 0; i < capabilities.count; i++) {
+ uint8_t capability = capabilities.data.u8[i];
+ if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME) {
+ isMonochrome = true;
+ }
+ }
+ mNeedFixupMonochromeTags = (isMonochrome && deviceVersion < CAMERA_DEVICE_API_VERSION_3_5);
+
+ return initializeCommonLocked();
+}
+
+hardware::Return<void> HidlCamera3Device::requestStreamBuffers(
+ const hardware::hidl_vec<hardware::camera::device::V3_5::BufferRequest>& bufReqs,
+ requestStreamBuffers_cb _hidl_cb) {
+ RequestBufferStates states {
+ mId, mRequestBufferInterfaceLock, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder,
+ *this, *mInterface, *this};
+ camera3::requestStreamBuffers(states, bufReqs, _hidl_cb);
+ return hardware::Void();
+}
+
+hardware::Return<void> HidlCamera3Device::returnStreamBuffers(
+ const hardware::hidl_vec<hardware::camera::device::V3_2::StreamBuffer>& buffers) {
+ ReturnBufferStates states {
+ mId, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder, *mInterface};
+ camera3::returnStreamBuffers(states, buffers);
+ return hardware::Void();
+}
+
+hardware::Return<void> HidlCamera3Device::processCaptureResult_3_4(
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_4::CaptureResult>& results) {
+ // Ideally we should grab mLock, but that can lead to deadlock, and
+ // it's not super important to get up to date value of mStatus for this
+ // warning print, hence skipping the lock here
+ if (mStatus == STATUS_ERROR) {
+ // Per API contract, HAL should act as closed after device error
+ // But mStatus can be set to error by framework as well, so just log
+ // a warning here.
+ ALOGW("%s: received capture result in error state.", __FUNCTION__);
+ }
+
+ sp<NotificationListener> listener;
+ {
+ std::lock_guard<std::mutex> l(mOutputLock);
+ listener = mListener.promote();
+ }
+
+ if (mProcessCaptureResultLock.tryLock() != OK) {
+ // This should never happen; it indicates a wrong client implementation
+ // that doesn't follow the contract. But, we can be tolerant here.
+ ALOGE("%s: callback overlapped! waiting 1s...",
+ __FUNCTION__);
+ if (mProcessCaptureResultLock.timedLock(1000000000 /* 1s */) != OK) {
+ ALOGE("%s: cannot acquire lock in 1s, dropping results",
+ __FUNCTION__);
+ // really don't know what to do, so bail out.
+ return hardware::Void();
+ }
+ }
+ HidlCaptureOutputStates states {
+ {
+ mId,
+ mInFlightLock, mLastCompletedRegularFrameNumber,
+ mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
+ mInFlightMap, mOutputLock, mResultQueue, mResultSignal,
+ mNextShutterFrameNumber,
+ mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
+ mNextResultFrameNumber,
+ mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
+ mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
+ mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
+ mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
+ mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
+ *mInterface, mLegacyClient}, mResultMetadataQueue
+ };
+
+ //HidlCaptureOutputStates hidlStates {
+ //}
+
+ for (const auto& result : results) {
+ processOneCaptureResultLocked(states, result.v3_2, result.physicalCameraMetadata);
+ }
+ mProcessCaptureResultLock.unlock();
+ return hardware::Void();
+}
+
+// Only one processCaptureResult should be called at a time, so
+// the locks won't block. The locks are present here simply to enforce this.
+hardware::Return<void> HidlCamera3Device::processCaptureResult(
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_2::CaptureResult>& results) {
+ hardware::hidl_vec<hardware::camera::device::V3_4::PhysicalCameraMetadata> noPhysMetadata;
+
+ // Ideally we should grab mLock, but that can lead to deadlock, and
+ // it's not super important to get up to date value of mStatus for this
+ // warning print, hence skipping the lock here
+ if (mStatus == STATUS_ERROR) {
+ // Per API contract, HAL should act as closed after device error
+ // But mStatus can be set to error by framework as well, so just log
+ // a warning here.
+ ALOGW("%s: received capture result in error state.", __FUNCTION__);
+ }
+
+ sp<NotificationListener> listener;
+ {
+ std::lock_guard<std::mutex> l(mOutputLock);
+ listener = mListener.promote();
+ }
+
+ if (mProcessCaptureResultLock.tryLock() != OK) {
+ // This should never happen; it indicates a wrong client implementation
+ // that doesn't follow the contract. But, we can be tolerant here.
+ ALOGE("%s: callback overlapped! waiting 1s...",
+ __FUNCTION__);
+ if (mProcessCaptureResultLock.timedLock(1000000000 /* 1s */) != OK) {
+ ALOGE("%s: cannot acquire lock in 1s, dropping results",
+ __FUNCTION__);
+ // really don't know what to do, so bail out.
+ return hardware::Void();
+ }
+ }
+
+ HidlCaptureOutputStates states {
+ {mId,
+ mInFlightLock, mLastCompletedRegularFrameNumber,
+ mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
+ mInFlightMap, mOutputLock, mResultQueue, mResultSignal,
+ mNextShutterFrameNumber,
+ mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
+ mNextResultFrameNumber,
+ mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
+ mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
+ mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
+ mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
+ mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
+ *mInterface, mLegacyClient}, mResultMetadataQueue
+ };
+
+ for (const auto& result : results) {
+ processOneCaptureResultLocked(states, result, noPhysMetadata);
+ }
+ mProcessCaptureResultLock.unlock();
+ return hardware::Void();
+}
+
+hardware::Return<void> HidlCamera3Device::notify(
+ const hardware::hidl_vec<hardware::camera::device::V3_2::NotifyMsg>& msgs) {
+ return notifyHelper<hardware::camera::device::V3_2::NotifyMsg>(msgs);
+}
+
+hardware::Return<void> HidlCamera3Device::notify_3_8(
+ const hardware::hidl_vec<hardware::camera::device::V3_8::NotifyMsg>& msgs) {
+ return notifyHelper<hardware::camera::device::V3_8::NotifyMsg>(msgs);
+}
+
+template<typename NotifyMsgType>
+hardware::Return<void> HidlCamera3Device::notifyHelper(
+ const hardware::hidl_vec<NotifyMsgType>& msgs) {
+ // Ideally we should grab mLock, but that can lead to deadlock, and
+ // it's not super important to get up to date value of mStatus for this
+ // warning print, hence skipping the lock here
+ if (mStatus == STATUS_ERROR) {
+ // Per API contract, HAL should act as closed after device error
+ // But mStatus can be set to error by framework as well, so just log
+ // a warning here.
+ ALOGW("%s: received notify message in error state.", __FUNCTION__);
+ }
+
+ sp<NotificationListener> listener;
+ {
+ std::lock_guard<std::mutex> l(mOutputLock);
+ listener = mListener.promote();
+ }
+
+ HidlCaptureOutputStates states {
+ {mId,
+ mInFlightLock, mLastCompletedRegularFrameNumber,
+ mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
+ mInFlightMap, mOutputLock, mResultQueue, mResultSignal,
+ mNextShutterFrameNumber,
+ mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
+ mNextResultFrameNumber,
+ mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
+ mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
+ mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
+ mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
+ mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
+ *mInterface, mLegacyClient}, mResultMetadataQueue
+ };
+ for (const auto& msg : msgs) {
+ camera3::notify(states, msg);
+ }
+ return hardware::Void();
+}
+
+status_t HidlCamera3Device::switchToOffline(
+ const std::vector<int32_t>& streamsToKeep,
+ /*out*/ sp<CameraOfflineSessionBase>* session) {
+ ATRACE_CALL();
+ if (session == nullptr) {
+ ALOGE("%s: session must not be null", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock il(mInterfaceLock);
+
+ bool hasInputStream = mInputStream != nullptr;
+ int32_t inputStreamId = hasInputStream ? mInputStream->getId() : -1;
+ bool inputStreamSupportsOffline = hasInputStream ?
+ mInputStream->getOfflineProcessingSupport() : false;
+ auto outputStreamIds = mOutputStreams.getStreamIds();
+ auto streamIds = outputStreamIds;
+ if (hasInputStream) {
+ streamIds.push_back(mInputStream->getId());
+ }
+
+ // Check all streams in streamsToKeep supports offline mode
+ for (auto id : streamsToKeep) {
+ if (std::find(streamIds.begin(), streamIds.end(), id) == streamIds.end()) {
+ ALOGE("%s: Unknown stream ID %d", __FUNCTION__, id);
+ return BAD_VALUE;
+ } else if (id == inputStreamId) {
+ if (!inputStreamSupportsOffline) {
+ ALOGE("%s: input stream %d cannot be switched to offline",
+ __FUNCTION__, id);
+ return BAD_VALUE;
+ }
+ } else {
+ sp<camera3::Camera3OutputStreamInterface> stream = mOutputStreams.get(id);
+ if (!stream->getOfflineProcessingSupport()) {
+ ALOGE("%s: output stream %d cannot be switched to offline",
+ __FUNCTION__, id);
+ return BAD_VALUE;
+ }
+ }
+ }
+ // TODO: block surface sharing and surface group streams until we can support them
+
+ // Stop repeating request, wait until all remaining requests are submitted, then call into
+ // HAL switchToOffline
+ hardware::camera::device::V3_6::CameraOfflineSessionInfo offlineSessionInfo;
+ sp<hardware::camera::device::V3_6::ICameraOfflineSession> offlineSession;
+ camera3::BufferRecords bufferRecords;
+ status_t ret = static_cast<HidlRequestThread *>(mRequestThread.get())->switchToOffline(
+ streamsToKeep, &offlineSessionInfo, &offlineSession, &bufferRecords);
+
+ if (ret != OK) {
+ SET_ERR("Switch to offline failed: %s (%d)", strerror(-ret), ret);
+ return ret;
+ }
+
+ bool succ = mRequestBufferSM.onSwitchToOfflineSuccess();
+ if (!succ) {
+ SET_ERR("HAL must not be calling requestStreamBuffers call");
+ // TODO: block ALL callbacks from HAL till app configured new streams?
+ return UNKNOWN_ERROR;
+ }
+
+ // Verify offlineSessionInfo
+ std::vector<int32_t> offlineStreamIds;
+ offlineStreamIds.reserve(offlineSessionInfo.offlineStreams.size());
+ for (auto offlineStream : offlineSessionInfo.offlineStreams) {
+ // verify stream IDs
+ int32_t id = offlineStream.id;
+ if (std::find(streamIds.begin(), streamIds.end(), id) == streamIds.end()) {
+ SET_ERR("stream ID %d not found!", id);
+ return UNKNOWN_ERROR;
+ }
+
+ // When not using HAL buf manager, only allow streams requested by app to be preserved
+ if (!mUseHalBufManager) {
+ if (std::find(streamsToKeep.begin(), streamsToKeep.end(), id) == streamsToKeep.end()) {
+ SET_ERR("stream ID %d must not be switched to offline!", id);
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ offlineStreamIds.push_back(id);
+ sp<Camera3StreamInterface> stream = (id == inputStreamId) ?
+ static_cast<sp<Camera3StreamInterface>>(mInputStream) :
+ static_cast<sp<Camera3StreamInterface>>(mOutputStreams.get(id));
+ // Verify number of outstanding buffers
+ if (stream->getOutstandingBuffersCount() != offlineStream.numOutstandingBuffers) {
+ SET_ERR("Offline stream %d # of remaining buffer mismatch: (%zu,%d) (service/HAL)",
+ id, stream->getOutstandingBuffersCount(), offlineStream.numOutstandingBuffers);
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ // Verify all streams to be deleted don't have any outstanding buffers
+ if (hasInputStream && std::find(offlineStreamIds.begin(), offlineStreamIds.end(),
+ inputStreamId) == offlineStreamIds.end()) {
+ if (mInputStream->hasOutstandingBuffers()) {
+ SET_ERR("Input stream %d still has %zu outstanding buffer!",
+ inputStreamId, mInputStream->getOutstandingBuffersCount());
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ for (const auto& outStreamId : outputStreamIds) {
+ if (std::find(offlineStreamIds.begin(), offlineStreamIds.end(),
+ outStreamId) == offlineStreamIds.end()) {
+ auto outStream = mOutputStreams.get(outStreamId);
+ if (outStream->hasOutstandingBuffers()) {
+ SET_ERR("Output stream %d still has %zu outstanding buffer!",
+ outStreamId, outStream->getOutstandingBuffersCount());
+ return UNKNOWN_ERROR;
+ }
+ }
+ }
+
+ InFlightRequestMap offlineReqs;
+ // Verify inflight requests and their pending buffers
+ {
+ std::lock_guard<std::mutex> l(mInFlightLock);
+ for (auto offlineReq : offlineSessionInfo.offlineRequests) {
+ int idx = mInFlightMap.indexOfKey(offlineReq.frameNumber);
+ if (idx == NAME_NOT_FOUND) {
+ SET_ERR("Offline request frame number %d not found!", offlineReq.frameNumber);
+ return UNKNOWN_ERROR;
+ }
+
+ const auto& inflightReq = mInFlightMap.valueAt(idx);
+ // TODO: check specific stream IDs
+ size_t numBuffersLeft = static_cast<size_t>(inflightReq.numBuffersLeft);
+ if (numBuffersLeft != offlineReq.pendingStreams.size()) {
+ SET_ERR("Offline request # of remaining buffer mismatch: (%d,%d) (service/HAL)",
+ inflightReq.numBuffersLeft, offlineReq.pendingStreams.size());
+ return UNKNOWN_ERROR;
+ }
+ offlineReqs.add(offlineReq.frameNumber, inflightReq);
+ }
+ }
+
+ // Create Camera3OfflineSession and transfer object ownership
+ // (streams, inflight requests, buffer caches)
+ camera3::StreamSet offlineStreamSet;
+ sp<camera3::Camera3Stream> inputStream;
+ for (auto offlineStream : offlineSessionInfo.offlineStreams) {
+ int32_t id = offlineStream.id;
+ if (mInputStream != nullptr && id == mInputStream->getId()) {
+ inputStream = mInputStream;
+ } else {
+ offlineStreamSet.add(id, mOutputStreams.get(id));
+ }
+ }
+
+ // TODO: check if we need to lock before copying states
+ // though technically no other thread should be talking to Camera3Device at this point
+ Camera3OfflineStates offlineStates(
+ mTagMonitor, mVendorTagId, mUseHalBufManager, mNeedFixupMonochromeTags,
+ mUsePartialResult, mNumPartialResults, mLastCompletedRegularFrameNumber,
+ mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
+ mNextResultFrameNumber, mNextReprocessResultFrameNumber,
+ mNextZslStillResultFrameNumber, mNextShutterFrameNumber,
+ mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
+ mDeviceInfo, mPhysicalDeviceInfoMap, mDistortionMappers,
+ mZoomRatioMappers, mRotateAndCropMappers);
+
+ *session = new HidlCamera3OfflineSession(mId, inputStream, offlineStreamSet,
+ std::move(bufferRecords), offlineReqs, offlineStates, offlineSession);
+
+ // Delete all streams that has been transferred to offline session
+ Mutex::Autolock l(mLock);
+ for (auto offlineStream : offlineSessionInfo.offlineStreams) {
+ int32_t id = offlineStream.id;
+ if (mInputStream != nullptr && id == mInputStream->getId()) {
+ mInputStream.clear();
+ } else {
+ mOutputStreams.remove(id);
+ }
+ }
+
+ // disconnect all other streams and switch to UNCONFIGURED state
+ if (mInputStream != nullptr) {
+ ret = mInputStream->disconnect();
+ if (ret != OK) {
+ SET_ERR_L("disconnect input stream failed!");
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ for (auto streamId : mOutputStreams.getStreamIds()) {
+ sp<Camera3StreamInterface> stream = mOutputStreams.get(streamId);
+ ret = stream->disconnect();
+ if (ret != OK) {
+ SET_ERR_L("disconnect output stream %d failed!", streamId);
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ mInputStream.clear();
+ mOutputStreams.clear();
+ mNeedConfig = true;
+ internalUpdateStatusLocked(STATUS_UNCONFIGURED);
+ mOperatingMode = NO_MODE;
+ mIsConstrainedHighSpeedConfiguration = false;
+ mRequestThread->clearPreviousRequest();
+
+ return OK;
+ // TO be done by CameraDeviceClient/Camera3OfflineSession
+ // register the offline client to camera service
+ // Setup result passthing threads etc
+ // Initialize offline session so HAL can start sending callback to it (result Fmq)
+ // TODO: check how many onIdle callback will be sent
+ // Java side to make sure the CameraCaptureSession is properly closed
+}
+
+sp<Camera3Device::RequestThread> HidlCamera3Device::createNewRequestThread(
+ wp<Camera3Device> parent, sp<camera3::StatusTracker> statusTracker,
+ sp<Camera3Device::HalInterface> interface,
+ const Vector<int32_t>& sessionParamKeys,
+ bool useHalBufManager,
+ bool supportCameraMute) {
+ return new HidlRequestThread(parent, statusTracker, interface, sessionParamKeys,
+ useHalBufManager, supportCameraMute);
+};
+
+sp<Camera3Device::Camera3DeviceInjectionMethods>
+HidlCamera3Device::createCamera3DeviceInjectionMethods(wp<Camera3Device> parent) {
+ return new HidlCamera3DeviceInjectionMethods(parent);
+}
+
+status_t HidlCamera3Device::injectionCameraInitialize(const String8 &injectedCamId,
+ sp<CameraProviderManager> manager) {
+ return (static_cast<HidlCamera3DeviceInjectionMethods *>(
+ mInjectionMethods.get()))->injectionInitialize(injectedCamId, manager, this);
+};
+
+
+HidlCamera3Device::HidlHalInterface::HidlHalInterface(
+ sp<device::V3_2::ICameraDeviceSession> &session,
+ std::shared_ptr<RequestMetadataQueue> queue,
+ bool useHalBufManager, bool supportOfflineProcessing) :
+ HalInterface(useHalBufManager, supportOfflineProcessing),
+ mHidlSession(session),
+ mRequestMetadataQueue(queue) {
+ // Check with hardware service manager if we can downcast these interfaces
+ // Somewhat expensive, so cache the results at startup
+ auto castResult_3_8 = device::V3_8::ICameraDeviceSession::castFrom(mHidlSession);
+ if (castResult_3_8.isOk()) {
+ mHidlSession_3_8 = castResult_3_8;
+ }
+ 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;
+ }
+ auto castResult_3_5 = device::V3_5::ICameraDeviceSession::castFrom(mHidlSession);
+ if (castResult_3_5.isOk()) {
+ mHidlSession_3_5 = castResult_3_5;
+ }
+ auto castResult_3_4 = device::V3_4::ICameraDeviceSession::castFrom(mHidlSession);
+ if (castResult_3_4.isOk()) {
+ mHidlSession_3_4 = castResult_3_4;
+ }
+ auto castResult_3_3 = device::V3_3::ICameraDeviceSession::castFrom(mHidlSession);
+ if (castResult_3_3.isOk()) {
+ mHidlSession_3_3 = castResult_3_3;
+ }
+}
+
+bool HidlCamera3Device::HidlHalInterface::valid() {
+ return (mHidlSession != nullptr);
+}
+
+void HidlCamera3Device::HidlHalInterface::clear() {
+ mHidlSession_3_8.clear();
+ mHidlSession_3_7.clear();
+ mHidlSession_3_6.clear();
+ mHidlSession_3_5.clear();
+ mHidlSession_3_4.clear();
+ mHidlSession_3_3.clear();
+ mHidlSession.clear();
+}
+
+status_t HidlCamera3Device::HidlHalInterface::constructDefaultRequestSettings(
+ camera_request_template_t templateId,
+ /*out*/ camera_metadata_t **requestTemplate) {
+ ATRACE_NAME("CameraHidlHal::constructDefaultRequestSettings");
+ if (!valid()) return INVALID_OPERATION;
+ status_t res = OK;
+
+ common::V1_0::Status status;
+
+ auto requestCallback = [&status, &requestTemplate]
+ (common::V1_0::Status s, const device::V3_2::CameraMetadata& request) {
+ status = s;
+ if (status == common::V1_0::Status::OK) {
+ const camera_metadata *r =
+ reinterpret_cast<const camera_metadata_t*>(request.data());
+ size_t expectedSize = request.size();
+ int ret = validate_camera_metadata_structure(r, &expectedSize);
+ if (ret == OK || ret == CAMERA_METADATA_VALIDATION_SHIFTED) {
+ *requestTemplate = clone_camera_metadata(r);
+ if (*requestTemplate == nullptr) {
+ ALOGE("%s: Unable to clone camera metadata received from HAL",
+ __FUNCTION__);
+ status = common::V1_0::Status::INTERNAL_ERROR;
+ }
+ } else {
+ ALOGE("%s: Malformed camera metadata received from HAL", __FUNCTION__);
+ status = common::V1_0::Status::INTERNAL_ERROR;
+ }
+ }
+ };
+ hardware::Return<void> err;
+ RequestTemplate id;
+ switch (templateId) {
+ case CAMERA_TEMPLATE_PREVIEW:
+ id = RequestTemplate::PREVIEW;
+ break;
+ case CAMERA_TEMPLATE_STILL_CAPTURE:
+ id = RequestTemplate::STILL_CAPTURE;
+ break;
+ case CAMERA_TEMPLATE_VIDEO_RECORD:
+ id = RequestTemplate::VIDEO_RECORD;
+ break;
+ case CAMERA_TEMPLATE_VIDEO_SNAPSHOT:
+ id = RequestTemplate::VIDEO_SNAPSHOT;
+ break;
+ case CAMERA_TEMPLATE_ZERO_SHUTTER_LAG:
+ id = RequestTemplate::ZERO_SHUTTER_LAG;
+ break;
+ case CAMERA_TEMPLATE_MANUAL:
+ id = RequestTemplate::MANUAL;
+ break;
+ default:
+ // Unknown template ID, or this HAL is too old to support it
+ return BAD_VALUE;
+ }
+ err = mHidlSession->constructDefaultRequestSettings(id, requestCallback);
+
+ if (!err.isOk()) {
+ ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+ res = DEAD_OBJECT;
+ } else {
+ res = HidlProviderInfo::mapToStatusT(status);
+ }
+
+ return res;
+}
+
+bool HidlCamera3Device::HidlHalInterface::isReconfigurationRequired(
+ CameraMetadata& oldSessionParams, CameraMetadata& newSessionParams) {
+ // We do reconfiguration by default;
+ bool ret = true;
+ if ((mHidlSession_3_5 != nullptr) && mIsReconfigurationQuerySupported) {
+ android::hardware::hidl_vec<uint8_t> oldParams, newParams;
+ camera_metadata_t* oldSessioMeta = const_cast<camera_metadata_t*>(
+ oldSessionParams.getAndLock());
+ camera_metadata_t* newSessioMeta = const_cast<camera_metadata_t*>(
+ newSessionParams.getAndLock());
+ oldParams.setToExternal(reinterpret_cast<uint8_t*>(oldSessioMeta),
+ get_camera_metadata_size(oldSessioMeta));
+ newParams.setToExternal(reinterpret_cast<uint8_t*>(newSessioMeta),
+ get_camera_metadata_size(newSessioMeta));
+ hardware::camera::common::V1_0::Status callStatus;
+ bool required;
+ auto hidlCb = [&callStatus, &required] (hardware::camera::common::V1_0::Status s,
+ bool requiredFlag) {
+ callStatus = s;
+ required = requiredFlag;
+ };
+ auto err = mHidlSession_3_5->isReconfigurationRequired(oldParams, newParams, hidlCb);
+ oldSessionParams.unlock(oldSessioMeta);
+ newSessionParams.unlock(newSessioMeta);
+ if (err.isOk()) {
+ switch (callStatus) {
+ case hardware::camera::common::V1_0::Status::OK:
+ ret = required;
+ break;
+ case hardware::camera::common::V1_0::Status::METHOD_NOT_SUPPORTED:
+ mIsReconfigurationQuerySupported = false;
+ ret = true;
+ break;
+ default:
+ ALOGV("%s: Reconfiguration query failed: %d", __FUNCTION__, callStatus);
+ ret = true;
+ }
+ } else {
+ ALOGE("%s: Unexpected binder error: %s", __FUNCTION__, err.description().c_str());
+ ret = true;
+ }
+ }
+
+ return ret;
+}
+
+status_t HidlCamera3Device::HidlHalInterface::configureStreams(
+ const camera_metadata_t *sessionParams,
+ camera_stream_configuration *config, const std::vector<uint32_t>& bufferSizes) {
+ ATRACE_NAME("CameraHal::configureStreams");
+ 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;
+ device::V3_8::StreamConfiguration requestedConfiguration3_8;
+ requestedConfiguration3_2.streams.resize(config->num_streams);
+ requestedConfiguration3_4.streams.resize(config->num_streams);
+ requestedConfiguration3_7.streams.resize(config->num_streams);
+ requestedConfiguration3_8.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];
+ device::V3_8::Stream &dst3_8 = requestedConfiguration3_8.streams[i];
+ camera3::camera_stream_t *src = config->streams[i];
+
+ Camera3Stream* cam3stream = Camera3Stream::cast(src);
+ cam3stream->setBufferFreedListener(this);
+ int streamId = cam3stream->getId();
+ StreamType streamType;
+ switch (src->stream_type) {
+ case CAMERA_STREAM_OUTPUT:
+ streamType = StreamType::OUTPUT;
+ break;
+ case CAMERA_STREAM_INPUT:
+ streamType = StreamType::INPUT;
+ break;
+ default:
+ ALOGE("%s: Stream %d: Unsupported stream type %d",
+ __FUNCTION__, streamId, config->streams[i]->stream_type);
+ return BAD_VALUE;
+ }
+ dst3_2.id = streamId;
+ dst3_2.streamType = streamType;
+ dst3_2.width = src->width;
+ dst3_2.height = src->height;
+ dst3_2.usage = mapToConsumerUsage(cam3stream->getUsage());
+ dst3_2.rotation = mapToStreamRotation((camera_stream_rotation_t) src->rotation);
+ // For HidlSession version 3.5 or newer, the format and dataSpace sent
+ // to HAL are original, not the overridden ones.
+ if (mHidlSession_3_5 != nullptr) {
+ dst3_2.format = mapToPixelFormat(cam3stream->isFormatOverridden() ?
+ cam3stream->getOriginalFormat() : src->format);
+ dst3_2.dataSpace = mapToHidlDataspace(cam3stream->isDataSpaceOverridden() ?
+ cam3stream->getOriginalDataSpace() : src->data_space);
+ } else {
+ dst3_2.format = mapToPixelFormat(src->format);
+ dst3_2.dataSpace = mapToHidlDataspace(src->data_space);
+ }
+ dst3_4.v3_2 = dst3_2;
+ dst3_4.bufferSize = bufferSizes[i];
+ if (src->physical_camera_id != nullptr) {
+ dst3_4.physicalCameraId = src->physical_camera_id;
+ }
+ dst3_7.v3_4 = dst3_4;
+ dst3_7.groupId = cam3stream->getHalStreamGroupId();
+ dst3_7.sensorPixelModesUsed.resize(src->sensor_pixel_modes_used.size());
+ size_t j = 0;
+ for (int mode : src->sensor_pixel_modes_used) {
+ dst3_7.sensorPixelModesUsed[j++] =
+ static_cast<CameraMetadataEnumAndroidSensorPixelMode>(mode);
+ }
+ if ((src->dynamic_range_profile !=
+ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD) &&
+ (mHidlSession_3_8 == nullptr)) {
+ ALOGE("%s: Camera device doesn't support non-standard dynamic range profiles: %d",
+ __FUNCTION__, src->dynamic_range_profile);
+ return BAD_VALUE;
+ }
+ dst3_8.v3_7 = dst3_7;
+ dst3_8.dynamicRangeProfile = mapToHidlDynamicProfile(src->dynamic_range_profile);
+ activeStreams.insert(streamId);
+ // Create Buffer ID map if necessary
+ mBufferRecords.tryCreateBufferCache(streamId);
+ }
+ // remove BufferIdMap for deleted streams
+ mBufferRecords.removeInactiveBufferCaches(activeStreams);
+
+ StreamConfigurationMode operationMode;
+ res = mapToStreamConfigurationMode(
+ (camera_stream_configuration_mode_t) config->operation_mode,
+ /*out*/ &operationMode);
+ if (res != OK) {
+ return res;
+ }
+ requestedConfiguration3_2.operationMode = operationMode;
+ requestedConfiguration3_4.operationMode = operationMode;
+ requestedConfiguration3_7.operationMode = operationMode;
+ size_t sessionParamSize = get_camera_metadata_size(sessionParams);
+ requestedConfiguration3_4.sessionParams.setToExternal(
+ reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(sessionParams)),
+ sessionParamSize);
+ requestedConfiguration3_7.operationMode = operationMode;
+ requestedConfiguration3_7.sessionParams.setToExternal(
+ reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(sessionParams)),
+ sessionParamSize);
+ requestedConfiguration3_8.operationMode = operationMode;
+ requestedConfiguration3_8.sessionParams.setToExternal(
+ reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(sessionParams)),
+ sessionParamSize);
+
+ // Invoke configureStreams
+ device::V3_3::HalStreamConfiguration finalConfiguration;
+ device::V3_4::HalStreamConfiguration finalConfiguration3_4;
+ device::V3_6::HalStreamConfiguration finalConfiguration3_6;
+ common::V1_0::Status status;
+
+ auto configStream34Cb = [&status, &finalConfiguration3_4]
+ (common::V1_0::Status s, const device::V3_4::HalStreamConfiguration& halConfiguration) {
+ finalConfiguration3_4 = halConfiguration;
+ status = s;
+ };
+
+ auto configStream36Cb = [&status, &finalConfiguration3_6]
+ (common::V1_0::Status s, const device::V3_6::HalStreamConfiguration& halConfiguration) {
+ finalConfiguration3_6 = halConfiguration;
+ status = s;
+ };
+
+ auto postprocConfigStream34 = [&finalConfiguration, &finalConfiguration3_4]
+ (hardware::Return<void>& err) -> status_t {
+ if (!err.isOk()) {
+ ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+ return DEAD_OBJECT;
+ }
+ finalConfiguration.streams.resize(finalConfiguration3_4.streams.size());
+ for (size_t i = 0; i < finalConfiguration3_4.streams.size(); i++) {
+ finalConfiguration.streams[i] = finalConfiguration3_4.streams[i].v3_3;
+ }
+ return OK;
+ };
+
+ auto postprocConfigStream36 = [&finalConfiguration, &finalConfiguration3_6]
+ (hardware::Return<void>& err) -> status_t {
+ if (!err.isOk()) {
+ ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+ return DEAD_OBJECT;
+ }
+ finalConfiguration.streams.resize(finalConfiguration3_6.streams.size());
+ for (size_t i = 0; i < finalConfiguration3_6.streams.size(); i++) {
+ finalConfiguration.streams[i] = finalConfiguration3_6.streams[i].v3_4.v3_3;
+ }
+ return OK;
+ };
+
+ // See which version of HAL we have
+ if (mHidlSession_3_8 != nullptr) {
+ ALOGV("%s: v3.8 device found", __FUNCTION__);
+ requestedConfiguration3_8.streamConfigCounter = mNextStreamConfigCounter++;
+ requestedConfiguration3_8.multiResolutionInputImage = config->input_is_multi_resolution;
+ auto err = mHidlSession_3_8->configureStreams_3_8(requestedConfiguration3_8,
+ configStream36Cb);
+ res = postprocConfigStream36(err);
+ if (res != OK) {
+ return res;
+ }
+ } else 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;
+ requestedConfiguration3_5.streamConfigCounter = mNextStreamConfigCounter++;
+ auto err = mHidlSession_3_6->configureStreams_3_6(
+ requestedConfiguration3_5, configStream36Cb);
+ res = postprocConfigStream36(err);
+ if (res != OK) {
+ return res;
+ }
+ } else if (mHidlSession_3_5 != nullptr) {
+ ALOGV("%s: v3.5 device found", __FUNCTION__);
+ device::V3_5::StreamConfiguration requestedConfiguration3_5;
+ requestedConfiguration3_5.v3_4 = requestedConfiguration3_4;
+ requestedConfiguration3_5.streamConfigCounter = mNextStreamConfigCounter++;
+ auto err = mHidlSession_3_5->configureStreams_3_5(
+ requestedConfiguration3_5, configStream34Cb);
+ res = postprocConfigStream34(err);
+ if (res != OK) {
+ return res;
+ }
+ } else if (mHidlSession_3_4 != nullptr) {
+ // We do; use v3.4 for the call
+ ALOGV("%s: v3.4 device found", __FUNCTION__);
+ auto err = mHidlSession_3_4->configureStreams_3_4(
+ requestedConfiguration3_4, configStream34Cb);
+ res = postprocConfigStream34(err);
+ if (res != OK) {
+ return res;
+ }
+ } else if (mHidlSession_3_3 != nullptr) {
+ // We do; use v3.3 for the call
+ ALOGV("%s: v3.3 device found", __FUNCTION__);
+ auto err = mHidlSession_3_3->configureStreams_3_3(requestedConfiguration3_2,
+ [&status, &finalConfiguration]
+ (common::V1_0::Status s, const device::V3_3::HalStreamConfiguration& halConfiguration) {
+ finalConfiguration = halConfiguration;
+ status = s;
+ });
+ if (!err.isOk()) {
+ ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+ return DEAD_OBJECT;
+ }
+ } else {
+ // We don't; use v3.2 call and construct a v3.3 HalStreamConfiguration
+ ALOGV("%s: v3.2 device found", __FUNCTION__);
+ HalStreamConfiguration finalConfiguration_3_2;
+ auto err = mHidlSession->configureStreams(requestedConfiguration3_2,
+ [&status, &finalConfiguration_3_2]
+ (common::V1_0::Status s, const HalStreamConfiguration& halConfiguration) {
+ finalConfiguration_3_2 = halConfiguration;
+ status = s;
+ });
+ if (!err.isOk()) {
+ ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+ return DEAD_OBJECT;
+ }
+ finalConfiguration.streams.resize(finalConfiguration_3_2.streams.size());
+ for (size_t i = 0; i < finalConfiguration_3_2.streams.size(); i++) {
+ finalConfiguration.streams[i].v3_2 = finalConfiguration_3_2.streams[i];
+ finalConfiguration.streams[i].overrideDataSpace =
+ requestedConfiguration3_2.streams[i].dataSpace;
+ }
+ }
+
+ if (status != common::V1_0::Status::OK ) {
+ return HidlProviderInfo::mapToStatusT(status);
+ }
+
+ // And convert output stream configuration from HIDL
+
+ for (size_t i = 0; i < config->num_streams; i++) {
+ camera3::camera_stream_t *dst = config->streams[i];
+ int streamId = Camera3Stream::cast(dst)->getId();
+
+ // Start scan at i, with the assumption that the stream order matches
+ size_t realIdx = i;
+ bool found = false;
+ size_t halStreamCount = finalConfiguration.streams.size();
+ for (size_t idx = 0; idx < halStreamCount; idx++) {
+ if (finalConfiguration.streams[realIdx].v3_2.id == streamId) {
+ found = true;
+ break;
+ }
+ realIdx = (realIdx >= halStreamCount - 1) ? 0 : realIdx + 1;
+ }
+ if (!found) {
+ ALOGE("%s: Stream %d not found in stream configuration response from HAL",
+ __FUNCTION__, streamId);
+ return INVALID_OPERATION;
+ }
+ device::V3_3::HalStream &src = finalConfiguration.streams[realIdx];
+ device::V3_6::HalStream &src_36 = finalConfiguration3_6.streams[realIdx];
+
+ Camera3Stream* dstStream = Camera3Stream::cast(dst);
+ int overrideFormat = mapToFrameworkFormat(src.v3_2.overrideFormat);
+ android_dataspace overrideDataSpace = mapToFrameworkDataspace(src.overrideDataSpace);
+
+ if (mHidlSession_3_6 != nullptr) {
+ dstStream->setOfflineProcessingSupport(src_36.supportOffline);
+ }
+
+ if (dstStream->getOriginalFormat() != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
+ dstStream->setFormatOverride(false);
+ dstStream->setDataSpaceOverride(false);
+ if (dst->format != overrideFormat) {
+ ALOGE("%s: Stream %d: Format override not allowed for format 0x%x", __FUNCTION__,
+ streamId, dst->format);
+ }
+ if (dst->data_space != overrideDataSpace) {
+ ALOGE("%s: Stream %d: DataSpace override not allowed for format 0x%x", __FUNCTION__,
+ streamId, dst->format);
+ }
+ } else {
+ bool needFormatOverride =
+ requestedConfiguration3_2.streams[i].format != src.v3_2.overrideFormat;
+ bool needDataspaceOverride =
+ requestedConfiguration3_2.streams[i].dataSpace != src.overrideDataSpace;
+ // Override allowed with IMPLEMENTATION_DEFINED
+ dstStream->setFormatOverride(needFormatOverride);
+ dstStream->setDataSpaceOverride(needDataspaceOverride);
+ dst->format = overrideFormat;
+ dst->data_space = overrideDataSpace;
+ }
+
+ if (dst->stream_type == CAMERA_STREAM_INPUT) {
+ if (src.v3_2.producerUsage != 0) {
+ ALOGE("%s: Stream %d: INPUT streams must have 0 for producer usage",
+ __FUNCTION__, streamId);
+ return INVALID_OPERATION;
+ }
+ dstStream->setUsage(
+ mapConsumerToFrameworkUsage(src.v3_2.consumerUsage));
+ } else {
+ // OUTPUT
+ if (src.v3_2.consumerUsage != 0) {
+ ALOGE("%s: Stream %d: OUTPUT streams must have 0 for consumer usage",
+ __FUNCTION__, streamId);
+ return INVALID_OPERATION;
+ }
+ dstStream->setUsage(
+ mapProducerToFrameworkUsage(src.v3_2.producerUsage));
+ }
+ dst->max_buffers = src.v3_2.maxBuffers;
+ }
+
+ return res;
+}
+
+status_t HidlCamera3Device::HidlHalInterface::configureInjectedStreams(
+ const camera_metadata_t* sessionParams, camera_stream_configuration* config,
+ const std::vector<uint32_t>& bufferSizes,
+ const CameraMetadata& cameraCharacteristics) {
+ ATRACE_NAME("InjectionCameraHal::configureStreams");
+ if (!valid()) return INVALID_OPERATION;
+ status_t res = OK;
+
+ if (config->input_is_multi_resolution) {
+ ALOGE("%s: Injection 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);
+ cam3stream->setBufferFreedListener(this);
+ int streamId = cam3stream->getId();
+ StreamType streamType;
+ switch (src->stream_type) {
+ case CAMERA_STREAM_OUTPUT:
+ streamType = StreamType::OUTPUT;
+ break;
+ case CAMERA_STREAM_INPUT:
+ streamType = StreamType::INPUT;
+ break;
+ default:
+ ALOGE("%s: Stream %d: Unsupported stream type %d", __FUNCTION__,
+ streamId, config->streams[i]->stream_type);
+ return BAD_VALUE;
+ }
+ dst3_2.id = streamId;
+ dst3_2.streamType = streamType;
+ dst3_2.width = src->width;
+ dst3_2.height = src->height;
+ dst3_2.usage = mapToConsumerUsage(cam3stream->getUsage());
+ dst3_2.rotation =
+ mapToStreamRotation((camera_stream_rotation_t)src->rotation);
+ // For HidlSession version 3.5 or newer, the format and dataSpace sent
+ // to HAL are original, not the overridden ones.
+ if (mHidlSession_3_5 != nullptr) {
+ dst3_2.format = mapToPixelFormat(cam3stream->isFormatOverridden()
+ ? cam3stream->getOriginalFormat()
+ : src->format);
+ dst3_2.dataSpace =
+ mapToHidlDataspace(cam3stream->isDataSpaceOverridden()
+ ? cam3stream->getOriginalDataSpace()
+ : src->data_space);
+ } else {
+ dst3_2.format = mapToPixelFormat(src->format);
+ dst3_2.dataSpace = mapToHidlDataspace(src->data_space);
+ }
+ dst3_4.v3_2 = dst3_2;
+ dst3_4.bufferSize = bufferSizes[i];
+ if (src->physical_camera_id != nullptr) {
+ dst3_4.physicalCameraId = src->physical_camera_id;
+ }
+ dst3_7.v3_4 = dst3_4;
+ dst3_7.groupId = cam3stream->getHalStreamGroupId();
+ dst3_7.sensorPixelModesUsed.resize(src->sensor_pixel_modes_used.size());
+ size_t j = 0;
+ for (int mode : src->sensor_pixel_modes_used) {
+ dst3_7.sensorPixelModesUsed[j++] =
+ static_cast<CameraMetadataEnumAndroidSensorPixelMode>(mode);
+ }
+ activeStreams.insert(streamId);
+ // Create Buffer ID map if necessary
+ mBufferRecords.tryCreateBufferCache(streamId);
+ }
+ // remove BufferIdMap for deleted streams
+ mBufferRecords.removeInactiveBufferCaches(activeStreams);
+
+ StreamConfigurationMode operationMode;
+ res = mapToStreamConfigurationMode(
+ (camera_stream_configuration_mode_t)config->operation_mode,
+ /*out*/ &operationMode);
+ if (res != OK) {
+ return res;
+ }
+ requestedConfiguration3_7.operationMode = operationMode;
+ size_t sessionParamSize = get_camera_metadata_size(sessionParams);
+ requestedConfiguration3_7.operationMode = operationMode;
+ requestedConfiguration3_7.sessionParams.setToExternal(
+ reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(sessionParams)),
+ sessionParamSize);
+
+ // See which version of HAL we have
+ if (mHidlSession_3_7 != nullptr) {
+ requestedConfiguration3_7.streamConfigCounter = mNextStreamConfigCounter++;
+ requestedConfiguration3_7.multiResolutionInputImage =
+ config->input_is_multi_resolution;
+
+ const camera_metadata_t* rawMetadata = cameraCharacteristics.getAndLock();
+ ::android::hardware::camera::device::V3_2::CameraMetadata hidlChars = {};
+ hidlChars.setToExternal(
+ reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(rawMetadata)),
+ get_camera_metadata_size(rawMetadata));
+ cameraCharacteristics.unlock(rawMetadata);
+
+ sp<hardware::camera::device::V3_7::ICameraInjectionSession>
+ hidlInjectionSession_3_7;
+ auto castInjectionResult_3_7 =
+ device::V3_7::ICameraInjectionSession::castFrom(mHidlSession_3_7);
+ if (castInjectionResult_3_7.isOk()) {
+ hidlInjectionSession_3_7 = castInjectionResult_3_7;
+ } else {
+ ALOGE("%s: Transaction error: %s", __FUNCTION__,
+ castInjectionResult_3_7.description().c_str());
+ return DEAD_OBJECT;
+ }
+
+ auto err = hidlInjectionSession_3_7->configureInjectionStreams(
+ requestedConfiguration3_7, hidlChars);
+ if (!err.isOk()) {
+ ALOGE("%s: Transaction error: %s", __FUNCTION__,
+ err.description().c_str());
+ return DEAD_OBJECT;
+ }
+ } else {
+ ALOGE("%s: mHidlSession_3_7 does not exist, the lowest version of injection "
+ "session is 3.7", __FUNCTION__);
+ return DEAD_OBJECT;
+ }
+
+ return res;
+}
+
+status_t HidlCamera3Device::HidlHalInterface::wrapAsHidlRequest(camera_capture_request_t* request,
+ /*out*/device::V3_2::CaptureRequest* captureRequest,
+ /*out*/std::vector<native_handle_t*>* handlesCreated,
+ /*out*/std::vector<std::pair<int32_t, int32_t>>* inflightBuffers) {
+ ATRACE_CALL();
+ if (captureRequest == nullptr || handlesCreated == nullptr || inflightBuffers == nullptr) {
+ ALOGE("%s: captureRequest (%p), handlesCreated (%p), and inflightBuffers(%p) "
+ "must not be null", __FUNCTION__, captureRequest, handlesCreated, inflightBuffers);
+ return BAD_VALUE;
+ }
+
+ captureRequest->frameNumber = request->frame_number;
+
+ captureRequest->fmqSettingsSize = 0;
+
+ {
+ if (request->input_buffer != nullptr) {
+ int32_t streamId = Camera3Stream::cast(request->input_buffer->stream)->getId();
+ buffer_handle_t buf = *(request->input_buffer->buffer);
+ auto pair = getBufferId(buf, streamId);
+ bool isNewBuffer = pair.first;
+ uint64_t bufferId = pair.second;
+ captureRequest->inputBuffer.streamId = streamId;
+ captureRequest->inputBuffer.bufferId = bufferId;
+ captureRequest->inputBuffer.buffer = (isNewBuffer) ? buf : nullptr;
+ captureRequest->inputBuffer.status = BufferStatus::OK;
+ native_handle_t *acquireFence = nullptr;
+ if (request->input_buffer->acquire_fence != -1) {
+ acquireFence = native_handle_create(1,0);
+ acquireFence->data[0] = request->input_buffer->acquire_fence;
+ handlesCreated->push_back(acquireFence);
+ }
+ captureRequest->inputBuffer.acquireFence = acquireFence;
+ captureRequest->inputBuffer.releaseFence = nullptr;
+
+ mBufferRecords.pushInflightBuffer(captureRequest->frameNumber, streamId,
+ request->input_buffer->buffer);
+ inflightBuffers->push_back(std::make_pair(captureRequest->frameNumber, streamId));
+ } else {
+ captureRequest->inputBuffer.streamId = -1;
+ captureRequest->inputBuffer.bufferId = BUFFER_ID_NO_BUFFER;
+ }
+
+ captureRequest->outputBuffers.resize(request->num_output_buffers);
+ for (size_t i = 0; i < request->num_output_buffers; i++) {
+ const camera_stream_buffer_t *src = request->output_buffers + i;
+ StreamBuffer &dst = captureRequest->outputBuffers[i];
+ int32_t streamId = Camera3Stream::cast(src->stream)->getId();
+ if (src->buffer != nullptr) {
+ buffer_handle_t buf = *(src->buffer);
+ auto pair = getBufferId(buf, streamId);
+ bool isNewBuffer = pair.first;
+ dst.bufferId = pair.second;
+ dst.buffer = isNewBuffer ? buf : nullptr;
+ native_handle_t *acquireFence = nullptr;
+ if (src->acquire_fence != -1) {
+ acquireFence = native_handle_create(1,0);
+ acquireFence->data[0] = src->acquire_fence;
+ handlesCreated->push_back(acquireFence);
+ }
+ dst.acquireFence = acquireFence;
+ } else if (mUseHalBufManager) {
+ // HAL buffer management path
+ dst.bufferId = BUFFER_ID_NO_BUFFER;
+ dst.buffer = nullptr;
+ dst.acquireFence = nullptr;
+ } else {
+ ALOGE("%s: cannot send a null buffer in capture request!", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ dst.streamId = streamId;
+ dst.status = BufferStatus::OK;
+ dst.releaseFence = nullptr;
+
+ // Output buffers are empty when using HAL buffer manager
+ if (!mUseHalBufManager) {
+ mBufferRecords.pushInflightBuffer(
+ captureRequest->frameNumber, streamId, src->buffer);
+ inflightBuffers->push_back(std::make_pair(captureRequest->frameNumber, streamId));
+ }
+ }
+ }
+ return OK;
+}
+
+status_t HidlCamera3Device::HidlHalInterface::flush() {
+ ATRACE_NAME("CameraHal::flush");
+ if (!valid()) return INVALID_OPERATION;
+ status_t res = OK;
+
+ auto err = mHidlSession->flush();
+ if (!err.isOk()) {
+ ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+ res = DEAD_OBJECT;
+ } else {
+ res = HidlProviderInfo::mapToStatusT(err);
+ }
+
+ return res;
+}
+
+status_t HidlCamera3Device::HidlHalInterface::dump(int /*fd*/) {
+ ATRACE_NAME("CameraHal::dump");
+ if (!valid()) return INVALID_OPERATION;
+
+ // Handled by CameraProviderManager::dump
+
+ return OK;
+}
+
+status_t HidlCamera3Device::HidlHalInterface::repeatingRequestEnd(uint32_t frameNumber,
+ const std::vector<int32_t> &streamIds) {
+ ATRACE_NAME("CameraHal::repeatingRequestEnd");
+ if (!valid()) return INVALID_OPERATION;
+
+ if (mHidlSession_3_8.get() != nullptr) {
+ mHidlSession_3_8->repeatingRequestEnd(frameNumber, streamIds);
+ }
+ return OK;
+}
+
+status_t HidlCamera3Device::HidlHalInterface::close() {
+ ATRACE_NAME("CameraHal::close()");
+ if (!valid()) return INVALID_OPERATION;
+ status_t res = OK;
+
+ auto err = mHidlSession->close();
+ // Interface will be dead shortly anyway, so don't log errors
+ if (!err.isOk()) {
+ res = DEAD_OBJECT;
+ }
+
+ return res;
+}
+
+void HidlCamera3Device::HidlHalInterface::signalPipelineDrain(const std::vector<int>& streamIds) {
+ ATRACE_NAME("CameraHal::signalPipelineDrain");
+ if (!valid() || mHidlSession_3_5 == nullptr) {
+ ALOGE("%s called on invalid camera!", __FUNCTION__);
+ return;
+ }
+
+ auto err = mHidlSession_3_5->signalStreamFlush(streamIds, mNextStreamConfigCounter - 1);
+ if (!err.isOk()) {
+ ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+ return;
+ }
+}
+
+status_t HidlCamera3Device::HidlHalInterface::processBatchCaptureRequests(
+ std::vector<camera_capture_request_t*>& requests,/*out*/uint32_t* numRequestProcessed) {
+ ATRACE_NAME("CameraHal::processBatchCaptureRequests");
+ 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;
+ }
+
+ 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_7 != nullptr) {
+ captureRequests_3_7.resize(batchSize);
+ } else if (hidlSession_3_4 != nullptr) {
+ captureRequests_3_4.resize(batchSize);
+ } else {
+ captureRequests.resize(batchSize);
+ }
+ std::vector<native_handle_t*> handlesCreated;
+ std::vector<std::pair<int32_t, int32_t>> inflightBuffers;
+
+ status_t res = OK;
+ for (size_t i = 0; i < batchSize; i++) {
+ 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 {
+ res = wrapAsHidlRequest(requests[i], /*out*/&captureRequests[i],
+ /*out*/&handlesCreated, /*out*/&inflightBuffers);
+ }
+ if (res != OK) {
+ mBufferRecords.popInflightBuffers(inflightBuffers);
+ cleanupNativeHandles(&handlesCreated);
+ return res;
+ }
+ }
+
+ std::vector<device::V3_2::BufferCache> cachesToRemove;
+ {
+ std::lock_guard<std::mutex> lock(mFreedBuffersLock);
+ for (auto& pair : mFreedBuffers) {
+ // The stream might have been removed since onBufferFreed
+ if (mBufferRecords.isStreamCached(pair.first)) {
+ cachesToRemove.push_back({pair.first, pair.second});
+ }
+ }
+ mFreedBuffers.clear();
+ }
+
+ common::V1_0::Status status = common::V1_0::Status::INTERNAL_ERROR;
+ *numRequestProcessed = 0;
+
+ // Write metadata to FMQ.
+ for (size_t i = 0; i < batchSize; i++) {
+ camera_capture_request_t* request = requests[i];
+ device::V3_2::CaptureRequest* captureRequest;
+ 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];
+ }
+
+ if (request->settings != nullptr) {
+ size_t settingsSize = get_camera_metadata_size(request->settings);
+ if (mRequestMetadataQueue != nullptr && mRequestMetadataQueue->write(
+ reinterpret_cast<const uint8_t*>(request->settings), settingsSize)) {
+ captureRequest->settings.resize(0);
+ captureRequest->fmqSettingsSize = settingsSize;
+ } else {
+ if (mRequestMetadataQueue != nullptr) {
+ ALOGW("%s: couldn't utilize fmq, fallback to hwbinder", __FUNCTION__);
+ }
+ captureRequest->settings.setToExternal(
+ reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(
+ request->settings)),
+ get_camera_metadata_size(request->settings));
+ captureRequest->fmqSettingsSize = 0u;
+ }
+ } else {
+ // A null request settings maps to a size-0 CameraMetadata
+ captureRequest->settings.resize(0);
+ captureRequest->fmqSettingsSize = 0u;
+ }
+
+ // 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)) {
+ physicalCameraSettings[j].settings.resize(0);
+ physicalCameraSettings[j].fmqSettingsSize = settingsSize;
+ } else {
+ if (mRequestMetadataQueue != nullptr) {
+ ALOGW("%s: couldn't utilize fmq, fallback to hwbinder", __FUNCTION__);
+ }
+ 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]));
+ physicalCameraSettings[j].fmqSettingsSize = 0u;
+ }
+ } else {
+ physicalCameraSettings[j].fmqSettingsSize = 0u;
+ physicalCameraSettings[j].settings.resize(0);
+ }
+ physicalCameraSettings[j].physicalCameraId = request->physcam_id[j];
+ }
+ }
+ }
+
+ hardware::details::return_status err;
+ auto resultCallback =
+ [&status, &numRequestProcessed] (auto s, uint32_t n) {
+ status = s;
+ *numRequestProcessed = n;
+ };
+ 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 {
+ err = mHidlSession->processCaptureRequest(captureRequests, cachesToRemove,
+ resultCallback);
+ }
+ if (!err.isOk()) {
+ ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+ status = common::V1_0::Status::CAMERA_DISCONNECTED;
+ }
+
+ if (status == common::V1_0::Status::OK && *numRequestProcessed != batchSize) {
+ ALOGE("%s: processCaptureRequest returns OK but processed %d/%zu requests",
+ __FUNCTION__, *numRequestProcessed, batchSize);
+ status = common::V1_0::Status::INTERNAL_ERROR;
+ }
+
+ res = HidlProviderInfo::mapToStatusT(status);
+ if (res == OK) {
+ if (mHidlSession->isRemote()) {
+ // Only close acquire fence FDs when the HIDL transaction succeeds (so the FDs have been
+ // sent to camera HAL processes)
+ cleanupNativeHandles(&handlesCreated, /*closeFd*/true);
+ } else {
+ // In passthrough mode the FDs are now owned by HAL
+ cleanupNativeHandles(&handlesCreated);
+ }
+ } else {
+ mBufferRecords.popInflightBuffers(inflightBuffers);
+ cleanupNativeHandles(&handlesCreated);
+ }
+ return res;
+}
+
+status_t HidlCamera3Device::HidlHalInterface::switchToOffline(
+ const std::vector<int32_t>& streamsToKeep,
+ /*out*/hardware::camera::device::V3_6::CameraOfflineSessionInfo* offlineSessionInfo,
+ /*out*/sp<hardware::camera::device::V3_6::ICameraOfflineSession>* offlineSession,
+ /*out*/camera3::BufferRecords* bufferRecords) {
+ ATRACE_NAME("CameraHal::switchToOffline");
+ if (!valid() || mHidlSession_3_6 == nullptr) {
+ ALOGE("%s called on invalid camera!", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ if (offlineSessionInfo == nullptr || offlineSession == nullptr || bufferRecords == nullptr) {
+ ALOGE("%s: output arguments must not be null!", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ common::V1_0::Status status = common::V1_0::Status::INTERNAL_ERROR;
+ auto resultCallback =
+ [&status, &offlineSessionInfo, &offlineSession] (auto s, auto info, auto session) {
+ status = s;
+ *offlineSessionInfo = info;
+ *offlineSession = session;
+ };
+ auto err = mHidlSession_3_6->switchToOffline(streamsToKeep, resultCallback);
+
+ if (!err.isOk()) {
+ ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+ return DEAD_OBJECT;
+ }
+
+ status_t ret = HidlProviderInfo::mapToStatusT(status);
+ if (ret != OK) {
+ return ret;
+ }
+
+ return verifyBufferCaches(offlineSessionInfo, bufferRecords);
+}
+
+HidlCamera3Device::HidlRequestThread::HidlRequestThread(wp<Camera3Device> parent,
+ sp<camera3::StatusTracker> statusTracker,
+ sp<HalInterface> interface,
+ const Vector<int32_t>& sessionParamKeys,
+ bool useHalBufManager,
+ bool supportCameraMute) :
+ RequestThread(parent, statusTracker, interface, sessionParamKeys, useHalBufManager,
+ supportCameraMute) {}
+
+status_t HidlCamera3Device::HidlRequestThread::switchToOffline(
+ const std::vector<int32_t>& streamsToKeep,
+ /*out*/hardware::camera::device::V3_6::CameraOfflineSessionInfo* offlineSessionInfo,
+ /*out*/sp<hardware::camera::device::V3_6::ICameraOfflineSession>* offlineSession,
+ /*out*/camera3::BufferRecords* bufferRecords) {
+ Mutex::Autolock l(mRequestLock);
+ clearRepeatingRequestsLocked(/*lastFrameNumber*/nullptr);
+
+ // Wait until request thread is fully stopped
+ // TBD: check if request thread is being paused by other APIs (shouldn't be)
+
+ // We could also check for mRepeatingRequests.empty(), but the API interface
+ // is serialized by Camera3Device::mInterfaceLock so no one should be able to submit any
+ // new requests during the call; hence skip that check.
+ bool queueEmpty = mNextRequests.empty() && mRequestQueue.empty();
+ while (!queueEmpty) {
+ status_t res = mRequestSubmittedSignal.waitRelative(mRequestLock, kRequestSubmitTimeout);
+ if (res == TIMED_OUT) {
+ ALOGE("%s: request thread failed to submit one request within timeout!", __FUNCTION__);
+ return res;
+ } else if (res != OK) {
+ ALOGE("%s: request thread failed to submit a request: %s (%d)!",
+ __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+ queueEmpty = mNextRequests.empty() && mRequestQueue.empty();
+ }
+ return (static_cast<HidlHalInterface *>(mInterface.get()))->switchToOffline(
+ streamsToKeep, offlineSessionInfo, offlineSession, bufferRecords);
+}
+
+status_t HidlCamera3Device::HidlCamera3DeviceInjectionMethods::injectionInitialize(
+ const String8& injectedCamId, sp<CameraProviderManager> manager,
+ const sp<android::hardware::camera::device::V3_2::ICameraDeviceCallback>&
+ callback) {
+ ATRACE_CALL();
+ Mutex::Autolock lock(mInjectionLock);
+
+ if (manager == nullptr) {
+ ALOGE("%s: manager does not exist!", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ sp<Camera3Device> parent = mParent.promote();
+ if (parent == nullptr) {
+ ALOGE("%s: parent does not exist!", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ mInjectedCamId = injectedCamId;
+ sp<ICameraDeviceSession> session;
+ ATRACE_BEGIN("Injection CameraHal::openSession");
+ status_t res = manager->openHidlSession(injectedCamId.string(), callback,
+ /*out*/ &session);
+ ATRACE_END();
+ if (res != OK) {
+ ALOGE("Injection camera could not open camera session: %s (%d)",
+ strerror(-res), res);
+ return res;
+ }
+
+ std::shared_ptr<RequestMetadataQueue> queue;
+ auto requestQueueRet =
+ session->getCaptureRequestMetadataQueue([&queue](const auto& descriptor) {
+ queue = std::make_shared<RequestMetadataQueue>(descriptor);
+ if (!queue->isValid() || queue->availableToWrite() <= 0) {
+ ALOGE("Injection camera HAL returns empty request metadata fmq, not "
+ "use it");
+ queue = nullptr;
+ // don't use the queue onwards.
+ }
+ });
+ if (!requestQueueRet.isOk()) {
+ ALOGE("Injection camera transaction error when getting request metadata fmq: "
+ "%s, not use it", requestQueueRet.description().c_str());
+ return DEAD_OBJECT;
+ }
+
+ std::unique_ptr<ResultMetadataQueue>& resQueue = mInjectionResultMetadataQueue;
+ auto resultQueueRet = session->getCaptureResultMetadataQueue(
+ [&resQueue](const auto& descriptor) {
+ resQueue = std::make_unique<ResultMetadataQueue>(descriptor);
+ if (!resQueue->isValid() || resQueue->availableToWrite() <= 0) {
+ ALOGE("Injection camera HAL returns empty result metadata fmq, not use "
+ "it");
+ resQueue = nullptr;
+ // Don't use the resQueue onwards.
+ }
+ });
+ if (!resultQueueRet.isOk()) {
+ ALOGE("Injection camera transaction error when getting result metadata queue "
+ "from camera session: %s", resultQueueRet.description().c_str());
+ return DEAD_OBJECT;
+ }
+ IF_ALOGV() {
+ session->interfaceChain(
+ [](::android::hardware::hidl_vec<::android::hardware::hidl_string>
+ interfaceChain) {
+ ALOGV("Injection camera session interface chain:");
+ for (const auto& iface : interfaceChain) {
+ ALOGV(" %s", iface.c_str());
+ }
+ });
+ }
+
+ ALOGV("%s: Injection camera interface = new HalInterface()", __FUNCTION__);
+
+ mInjectedCamHalInterface =
+ new HidlHalInterface(session, queue, parent->mUseHalBufManager,
+ parent->mSupportOfflineProcessing);
+ if (mInjectedCamHalInterface == nullptr) {
+ ALOGE("%s: mInjectedCamHalInterface does not exist!", __FUNCTION__);
+ return DEAD_OBJECT;
+ }
+
+ return OK;
+}
+
+status_t HidlCamera3Device::HidlCamera3DeviceInjectionMethods::replaceHalInterface(
+ sp<HalInterface> newHalInterface, bool keepBackup) {
+ Mutex::Autolock lock(mInjectionLock);
+ if (newHalInterface.get() == nullptr) {
+ ALOGE("%s: The newHalInterface does not exist, to stop replacing.",
+ __FUNCTION__);
+ return DEAD_OBJECT;
+ }
+
+ sp<Camera3Device> parent = mParent.promote();
+ if (parent == nullptr) {
+ ALOGE("%s: parent does not exist!", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ if (newHalInterface->getTransportType() != IPCTransport::HIDL) {
+ ALOGE("%s Replacing HIDL HalInterface with another transport unsupported", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ HidlCamera3Device *hidlParent = static_cast<HidlCamera3Device *>(parent.get());
+ if (keepBackup) {
+ if (mBackupHalInterface == nullptr) {
+ mBackupHalInterface = parent->mInterface;
+ }
+ if (mBackupResultMetadataQueue == nullptr) {
+ mBackupResultMetadataQueue = std::move(hidlParent->mResultMetadataQueue);
+ hidlParent->mResultMetadataQueue = std::move(mInjectionResultMetadataQueue);
+ }
+ } else {
+ mBackupHalInterface = nullptr;
+ hidlParent->mResultMetadataQueue = std::move(mBackupResultMetadataQueue);
+ mBackupResultMetadataQueue = nullptr;
+ }
+ parent->mInterface = newHalInterface;
+
+ return OK;
+}
+
+}; // namespace android
diff --git a/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.h b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.h
new file mode 100644
index 0000000..a83080b
--- /dev/null
+++ b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.h
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2022 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_SERVERS_HIDLCAMERA3DEVICE_H
+#define ANDROID_SERVERS_HIDLCAMERA3DEVICE_H
+
+#include "../Camera3Device.h"
+#include "HidlCamera3OutputUtils.h"
+
+namespace android {
+
+using android::hardware::camera::metadata::V3_8::CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap;
+
+/**
+ * CameraDevice for HIDL HAL devices with version CAMERA_DEVICE_API_VERSION_3_0 or higher.
+ */
+class HidlCamera3Device :
+ virtual public hardware::camera::device::V3_8::ICameraDeviceCallback,
+ public Camera3Device {
+ public:
+
+ explicit HidlCamera3Device(const String8& id, bool overrideForPerfClass,
+ bool legacyClient = false) : Camera3Device(id, overrideForPerfClass, legacyClient) { }
+
+ virtual ~HidlCamera3Device() {}
+
+ /**
+ * Helper functions to map between framework and HIDL values
+ */
+ static hardware::graphics::common::V1_0::PixelFormat mapToPixelFormat(int frameworkFormat);
+ static hardware::camera::device::V3_2::DataspaceFlags mapToHidlDataspace(
+ android_dataspace dataSpace);
+ static hardware::camera::device::V3_2::BufferUsageFlags mapToConsumerUsage(uint64_t usage);
+ static CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap mapToHidlDynamicProfile(
+ int dynamicRangeProfile);
+ static hardware::camera::device::V3_2::StreamRotation mapToStreamRotation(
+ camera_stream_rotation_t rotation);
+ // Returns a negative error code if the passed-in operation mode is not valid.
+ static status_t mapToStreamConfigurationMode(camera_stream_configuration_mode_t operationMode,
+ /*out*/ hardware::camera::device::V3_2::StreamConfigurationMode *mode);
+ static int mapToFrameworkFormat(hardware::graphics::common::V1_0::PixelFormat pixelFormat);
+ static android_dataspace mapToFrameworkDataspace(
+ hardware::camera::device::V3_2::DataspaceFlags);
+ static uint64_t mapConsumerToFrameworkUsage(
+ hardware::camera::device::V3_2::BufferUsageFlags usage);
+ static uint64_t mapProducerToFrameworkUsage(
+ hardware::camera::device::V3_2::BufferUsageFlags usage);
+
+ status_t initialize(sp<CameraProviderManager> manager, const String8& monitorTags) override;
+
+ /**
+ * Implementation of android::hardware::camera::device::V3_5::ICameraDeviceCallback
+ */
+
+ hardware::Return<void> processCaptureResult_3_4(
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_4::CaptureResult>& results) override;
+ hardware::Return<void> processCaptureResult(
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_2::CaptureResult>& results) override;
+ hardware::Return<void> notify(
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_2::NotifyMsg>& msgs) override;
+
+ hardware::Return<void> requestStreamBuffers(
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_5::BufferRequest>& bufReqs,
+ requestStreamBuffers_cb _hidl_cb) override;
+
+ hardware::Return<void> returnStreamBuffers(
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_2::StreamBuffer>& buffers) override;
+
+ hardware::Return<void> notify_3_8(
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_8::NotifyMsg>& msgs) override;
+
+ // Handle one notify message
+ void notify(const hardware::camera::device::V3_2::NotifyMsg& msg);
+
+ status_t switchToOffline(const std::vector<int32_t>& streamsToKeep,
+ /*out*/ sp<CameraOfflineSessionBase>* session) override;
+
+ using RequestMetadataQueue = hardware::MessageQueue<uint8_t, hardware::kSynchronizedReadWrite>;
+
+ class HidlHalInterface : public Camera3Device::HalInterface {
+ public:
+ HidlHalInterface(sp<hardware::camera::device::V3_2::ICameraDeviceSession> &session,
+ std::shared_ptr<RequestMetadataQueue> queue,
+ bool useHalBufManager, bool supportOfflineProcessing);
+
+ virtual IPCTransport getTransportType() override { return IPCTransport::HIDL; }
+ // Returns true if constructed with a valid device or session, and not yet cleared
+ virtual bool valid() override;
+
+ // Reset this HalInterface object (does not call close())
+ virtual void clear() override;
+
+ // Calls into the HAL interface
+
+ // Caller takes ownership of requestTemplate
+ virtual status_t constructDefaultRequestSettings(camera_request_template templateId,
+ /*out*/ camera_metadata_t **requestTemplate) override;
+
+ virtual status_t configureStreams(const camera_metadata_t *sessionParams,
+ /*inout*/ camera_stream_configuration_t *config,
+ const std::vector<uint32_t>& bufferSizes) override;
+
+ // The injection camera configures the streams to hal.
+ virtual status_t configureInjectedStreams(
+ const camera_metadata_t* sessionParams,
+ /*inout*/ camera_stream_configuration_t* config,
+ const std::vector<uint32_t>& bufferSizes,
+ const CameraMetadata& cameraCharacteristics) override;
+
+ // When the call succeeds, the ownership of acquire fences in requests is transferred to
+ // HalInterface. More specifically, the current implementation will send the fence to
+ // HAL process and close the FD in cameraserver process. When the call fails, the ownership
+ // of the acquire fence still belongs to the caller.
+ virtual status_t processBatchCaptureRequests(
+ std::vector<camera_capture_request_t*>& requests,
+ /*out*/uint32_t* numRequestProcessed) override;
+ virtual status_t flush() override;
+ virtual status_t dump(int fd) override;
+ virtual status_t close() override;
+
+ virtual void signalPipelineDrain(const std::vector<int>& streamIds) override;
+ virtual bool isReconfigurationRequired(CameraMetadata& oldSessionParams,
+ CameraMetadata& newSessionParams) override;
+
+ virtual status_t repeatingRequestEnd(uint32_t frameNumber,
+ const std::vector<int32_t> &streamIds) override;
+
+ status_t switchToOffline(
+ const std::vector<int32_t>& streamsToKeep,
+ /*out*/hardware::camera::device::V3_6::CameraOfflineSessionInfo* offlineSessionInfo,
+ /*out*/sp<hardware::camera::device::V3_6::ICameraOfflineSession>* offlineSession,
+ /*out*/camera3::BufferRecords* bufferRecords);
+
+ private:
+
+ // Always valid
+ sp<hardware::camera::device::V3_2::ICameraDeviceSession> mHidlSession;
+ // Valid if ICameraDeviceSession is @3.3 or newer
+ sp<hardware::camera::device::V3_3::ICameraDeviceSession> mHidlSession_3_3;
+ // Valid if ICameraDeviceSession is @3.4 or newer
+ sp<hardware::camera::device::V3_4::ICameraDeviceSession> mHidlSession_3_4;
+ // Valid if ICameraDeviceSession is @3.5 or newer
+ 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;
+ // Valid if ICameraDeviceSession is @3.7 or newer
+ sp<hardware::camera::device::V3_8::ICameraDeviceSession> mHidlSession_3_8;
+
+ std::shared_ptr<RequestMetadataQueue> mRequestMetadataQueue;
+
+ // The output HIDL request still depends on input camera_capture_request_t
+ // Do not free input camera_capture_request_t before output HIDL request
+ status_t wrapAsHidlRequest(camera_capture_request_t* in,
+ /*out*/hardware::camera::device::V3_2::CaptureRequest* out,
+ /*out*/std::vector<native_handle_t*>* handlesCreated,
+ /*out*/std::vector<std::pair<int32_t, int32_t>>* inflightBuffers);
+ }; // class HidlHalInterface
+
+ class HidlRequestThread : public Camera3Device::RequestThread {
+ public:
+ HidlRequestThread(wp<Camera3Device> parent,
+ sp<camera3::StatusTracker> statusTracker,
+ sp<HalInterface> interface,
+ const Vector<int32_t>& sessionParamKeys,
+ bool useHalBufManager,
+ bool supportCameraMute);
+
+ status_t switchToOffline(
+ const std::vector<int32_t>& streamsToKeep,
+ /*out*/hardware::camera::device::V3_6::CameraOfflineSessionInfo* offlineSessionInfo,
+ /*out*/sp<hardware::camera::device::V3_6::ICameraOfflineSession>* offlineSession,
+ /*out*/camera3::BufferRecords* bufferRecords);
+ }; // class HidlRequestThread
+
+ class HidlCamera3DeviceInjectionMethods : public Camera3DeviceInjectionMethods {
+ public:
+ // Initialize the injection camera and generate an hal interface.
+ status_t injectionInitialize(
+ const String8& injectedCamId, sp<CameraProviderManager> manager,
+ const sp<
+ android::hardware::camera::device::V3_2 ::ICameraDeviceCallback>&
+ callback);
+ HidlCamera3DeviceInjectionMethods(wp<Camera3Device> parent) :
+ Camera3DeviceInjectionMethods(parent) { };
+ ~HidlCamera3DeviceInjectionMethods() {}
+ private:
+ // Backup of the original camera hal result FMQ.
+ std::unique_ptr<ResultMetadataQueue> mBackupResultMetadataQueue;
+
+ // FMQ writes the result for the injection camera. Must be guarded by
+ // mProcessCaptureResultLock.
+ std::unique_ptr<ResultMetadataQueue> mInjectionResultMetadataQueue;
+
+ // Use injection camera hal interface to replace and backup original
+ // camera hal interface.
+ virtual status_t replaceHalInterface(sp<HalInterface> newHalInterface,
+ bool keepBackup) override;
+ };
+
+ private:
+ template<typename NotifyMsgType>
+ hardware::Return<void> notifyHelper(
+ const hardware::hidl_vec<NotifyMsgType>& msgs);
+
+ virtual status_t injectionCameraInitialize(const String8 &injectCamId,
+ sp<CameraProviderManager> manager) override;
+
+ virtual sp<RequestThread> createNewRequestThread(wp<Camera3Device> parent,
+ sp<camera3::StatusTracker> statusTracker,
+ sp<HalInterface> interface,
+ const Vector<int32_t>& sessionParamKeys,
+ bool useHalBufManager,
+ bool supportCameraMute) override;
+
+ virtual sp<Camera3DeviceInjectionMethods>
+ createCamera3DeviceInjectionMethods(wp<Camera3Device>) override;
+
+ // FMQ to write result on. Must be guarded by mProcessCaptureResultLock.
+ std::unique_ptr<ResultMetadataQueue> mResultMetadataQueue;
+
+}; // class HidlCamera3Device
+
+}; // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/device3/hidl/HidlCamera3OfflineSession.cpp b/services/camera/libcameraservice/device3/hidl/HidlCamera3OfflineSession.cpp
new file mode 100644
index 0000000..d517c8d
--- /dev/null
+++ b/services/camera/libcameraservice/device3/hidl/HidlCamera3OfflineSession.cpp
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Hidl-Camera3-OffLnSsn"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
+#include <inttypes.h>
+
+#include <utils/Trace.h>
+
+#include <android/hardware/camera2/ICameraDeviceCallbacks.h>
+
+#include "device3/hidl/HidlCamera3OfflineSession.h"
+#include "device3/Camera3OutputStream.h"
+#include "device3/hidl/HidlCamera3OutputUtils.h"
+#include "device3/Camera3InputStream.h"
+#include "device3/Camera3SharedOutputStream.h"
+#include "utils/CameraTraces.h"
+
+using namespace android::camera3;
+using namespace android::hardware::camera;
+
+namespace android {
+
+HidlCamera3OfflineSession::~HidlCamera3OfflineSession() {
+ ATRACE_CALL();
+ ALOGV("%s: Tearing down hidl offline session for camera id %s", __FUNCTION__, mId.string());
+ HidlCamera3OfflineSession::disconnectSession();
+}
+
+status_t HidlCamera3OfflineSession::initialize(wp<NotificationListener> listener) {
+ ATRACE_CALL();
+
+ if (mSession == nullptr) {
+ ALOGE("%s: HIDL session is null!", __FUNCTION__);
+ return DEAD_OBJECT;
+ }
+
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+
+ mListener = listener;
+
+ // setup result FMQ
+ std::unique_ptr<ResultMetadataQueue>& resQueue = mResultMetadataQueue;
+ auto resultQueueRet = mSession->getCaptureResultMetadataQueue(
+ [&resQueue](const auto& descriptor) {
+ resQueue = std::make_unique<ResultMetadataQueue>(descriptor);
+ if (!resQueue->isValid() || resQueue->availableToWrite() <= 0) {
+ ALOGE("HAL returns empty result metadata fmq, not use it");
+ resQueue = nullptr;
+ // Don't use resQueue onwards.
+ }
+ });
+ if (!resultQueueRet.isOk()) {
+ ALOGE("Transaction error when getting result metadata queue from camera session: %s",
+ resultQueueRet.description().c_str());
+ return DEAD_OBJECT;
+ }
+ mStatus = STATUS_ACTIVE;
+ }
+
+ mSession->setCallback(this);
+
+ return OK;
+}
+
+hardware::Return<void> HidlCamera3OfflineSession::processCaptureResult_3_4(
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_4::CaptureResult>& results) {
+ sp<NotificationListener> listener;
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+ if (mStatus != STATUS_ACTIVE) {
+ ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
+ return hardware::Void();
+ }
+ listener = mListener.promote();
+ }
+
+ HidlCaptureOutputStates states {
+ {mId,
+ mOfflineReqsLock, mLastCompletedRegularFrameNumber,
+ mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
+ mOfflineReqs, mOutputLock, mResultQueue, mResultSignal,
+ mNextShutterFrameNumber,
+ mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
+ mNextResultFrameNumber,
+ mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
+ mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
+ mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
+ mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
+ mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
+ mBufferRecords, /*legacyClient*/ false}, mResultMetadataQueue
+ };
+
+ std::lock_guard<std::mutex> lock(mProcessCaptureResultLock);
+ for (const auto& result : results) {
+ processOneCaptureResultLocked(states, result.v3_2, result.physicalCameraMetadata);
+ }
+ return hardware::Void();
+}
+
+hardware::Return<void> HidlCamera3OfflineSession::processCaptureResult(
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_2::CaptureResult>& results) {
+ // TODO: changed impl to call into processCaptureResult_3_4 instead?
+ // might need to figure how to reduce copy though.
+ sp<NotificationListener> listener;
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+ if (mStatus != STATUS_ACTIVE) {
+ ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
+ return hardware::Void();
+ }
+ listener = mListener.promote();
+ }
+
+ hardware::hidl_vec<hardware::camera::device::V3_4::PhysicalCameraMetadata> noPhysMetadata;
+
+ HidlCaptureOutputStates states {
+ {mId,
+ mOfflineReqsLock, mLastCompletedRegularFrameNumber,
+ mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
+ mOfflineReqs, mOutputLock, mResultQueue, mResultSignal,
+ mNextShutterFrameNumber,
+ mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
+ mNextResultFrameNumber,
+ mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
+ mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
+ mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
+ mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
+ mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
+ mBufferRecords, /*legacyClient*/ false}, mResultMetadataQueue
+ };
+
+ std::lock_guard<std::mutex> lock(mProcessCaptureResultLock);
+ for (const auto& result : results) {
+ processOneCaptureResultLocked(states, result, noPhysMetadata);
+ }
+ return hardware::Void();
+}
+
+hardware::Return<void> HidlCamera3OfflineSession::notify(
+ const hardware::hidl_vec<hardware::camera::device::V3_2::NotifyMsg>& msgs) {
+ sp<NotificationListener> listener;
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+ if (mStatus != STATUS_ACTIVE) {
+ ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
+ return hardware::Void();
+ }
+ listener = mListener.promote();
+ }
+
+ HidlCaptureOutputStates states {
+ {mId,
+ mOfflineReqsLock, mLastCompletedRegularFrameNumber,
+ mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
+ mOfflineReqs, mOutputLock, mResultQueue, mResultSignal,
+ mNextShutterFrameNumber,
+ mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
+ mNextResultFrameNumber,
+ mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
+ mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
+ mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
+ mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
+ mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
+ mBufferRecords, /*legacyClient*/ false}, mResultMetadataQueue
+ };
+ for (const auto& msg : msgs) {
+ camera3::notify(states, msg);
+ }
+ return hardware::Void();
+}
+
+hardware::Return<void> HidlCamera3OfflineSession::requestStreamBuffers(
+ const hardware::hidl_vec<hardware::camera::device::V3_5::BufferRequest>& bufReqs,
+ requestStreamBuffers_cb _hidl_cb) {
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+ if (mStatus != STATUS_ACTIVE) {
+ ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
+ return hardware::Void();
+ }
+ }
+
+ RequestBufferStates states {
+ mId, mRequestBufferInterfaceLock, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder,
+ *this, mBufferRecords, *this};
+ camera3::requestStreamBuffers(states, bufReqs, _hidl_cb);
+ return hardware::Void();
+}
+
+hardware::Return<void> HidlCamera3OfflineSession::returnStreamBuffers(
+ const hardware::hidl_vec<hardware::camera::device::V3_2::StreamBuffer>& buffers) {
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+ if (mStatus != STATUS_ACTIVE) {
+ ALOGE("%s called in wrong state %d", __FUNCTION__, mStatus);
+ return hardware::Void();
+ }
+ }
+
+ ReturnBufferStates states {
+ mId, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder, mBufferRecords};
+
+ camera3::returnStreamBuffers(states, buffers);
+ return hardware::Void();
+}
+
+void HidlCamera3OfflineSession::disconnectSession() {
+ // TODO: Make sure this locking is correct.
+ std::lock_guard<std::mutex> lock(mLock);
+ if (mSession != nullptr) {
+ mSession->close();
+ }
+ mSession.clear();
+}
+
+}; // namespace android
diff --git a/services/camera/libcameraservice/device3/hidl/HidlCamera3OfflineSession.h b/services/camera/libcameraservice/device3/hidl/HidlCamera3OfflineSession.h
new file mode 100644
index 0000000..597cc5d
--- /dev/null
+++ b/services/camera/libcameraservice/device3/hidl/HidlCamera3OfflineSession.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2022 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_SERVERS_HIDL_CAMERA3OFFLINESESSION_H
+#define ANDROID_SERVERS_HIDL_CAMERA3OFFLINESESSION_H
+
+#include <memory>
+#include <mutex>
+
+#include <utils/String8.h>
+#include <utils/String16.h>
+
+#include <android/hardware/camera/device/3.6/ICameraOfflineSession.h>
+
+#include <fmq/MessageQueue.h>
+
+#include "HidlCamera3OutputUtils.h"
+#include "common/CameraOfflineSessionBase.h"
+
+#include "device3/Camera3BufferManager.h"
+#include "device3/Camera3OfflineSession.h"
+#include "device3/InFlightRequest.h"
+
+namespace android {
+
+namespace camera3 {
+
+class Camera3Stream;
+class Camera3OutputStreamInterface;
+class Camera3StreamInterface;
+
+} // namespace camera3
+
+/**
+ * HidlCamera3OfflineSession for offline session defined in HIDL ICameraOfflineSession@3.6 or higher
+ */
+class HidlCamera3OfflineSession :
+ public Camera3OfflineSession,
+ virtual public hardware::camera::device::V3_5::ICameraDeviceCallback {
+ public:
+
+ // initialize by Camera3Device.
+ explicit HidlCamera3OfflineSession(const String8& id,
+ const sp<camera3::Camera3Stream>& inputStream,
+ const camera3::StreamSet& offlineStreamSet,
+ camera3::BufferRecords&& bufferRecords,
+ const camera3::InFlightRequestMap& offlineReqs,
+ const Camera3OfflineStates& offlineStates,
+ sp<hardware::camera::device::V3_6::ICameraOfflineSession> offlineSession) :
+ Camera3OfflineSession(id, inputStream, offlineStreamSet, std::move(bufferRecords),
+ offlineReqs, offlineStates),
+ mSession(offlineSession) {};
+
+ virtual ~HidlCamera3OfflineSession();
+
+ virtual status_t initialize(wp<NotificationListener> listener) override;
+
+ /**
+ * HIDL ICameraDeviceCallback interface
+ * Implementation of android::hardware::camera::device::V3_5::ICameraDeviceCallback
+ */
+
+ hardware::Return<void> processCaptureResult_3_4(
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_4::CaptureResult>& results) override;
+ hardware::Return<void> processCaptureResult(
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_2::CaptureResult>& results) override;
+ hardware::Return<void> notify(
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_2::NotifyMsg>& msgs) override;
+
+ hardware::Return<void> requestStreamBuffers(
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_5::BufferRequest>& bufReqs,
+ requestStreamBuffers_cb _hidl_cb) override;
+
+ hardware::Return<void> returnStreamBuffers(
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_2::StreamBuffer>& buffers) override;
+
+ /**
+ * End of CameraOfflineSessionBase interface
+ */
+
+ private:
+ sp<hardware::camera::device::V3_6::ICameraOfflineSession> mSession;
+ // FMQ to write result on. Must be guarded by mProcessCaptureResultLock.
+ std::unique_ptr<ResultMetadataQueue> mResultMetadataQueue;
+
+ virtual void disconnectSession() override;
+}; // class Camera3OfflineSession
+
+}; // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/device3/hidl/HidlCamera3OutputUtils.cpp b/services/camera/libcameraservice/device3/hidl/HidlCamera3OutputUtils.cpp
new file mode 100644
index 0000000..afe9d56
--- /dev/null
+++ b/services/camera/libcameraservice/device3/hidl/HidlCamera3OutputUtils.cpp
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "HidlCamera3-OutputUtils"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+// Convenience macros for transitioning to the error state
+#define SET_ERR(fmt, ...) states.setErrIntf.setErrorState( \
+ "%s: " fmt, __FUNCTION__, \
+ ##__VA_ARGS__)
+
+#include <inttypes.h>
+
+#include <utils/Log.h>
+#include <utils/SortedVector.h>
+#include <utils/Trace.h>
+
+#include <android/hardware/camera2/ICameraDeviceCallbacks.h>
+
+#include <android/hardware/camera/device/3.4/ICameraDeviceCallback.h>
+#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
+#include <android/hardware/camera/device/3.5/ICameraDeviceSession.h>
+
+#include <camera/CameraUtils.h>
+#include <camera_metadata_hidden.h>
+
+#include "device3/hidl/HidlCamera3OutputUtils.h"
+#include "device3/Camera3OutputUtilsTemplated.h"
+
+#include "system/camera_metadata.h"
+
+using namespace android::camera3;
+using namespace android::hardware::camera;
+
+namespace android {
+namespace camera3 {
+
+void processOneCaptureResultLocked(
+ HidlCaptureOutputStates& states,
+ const hardware::camera::device::V3_2::CaptureResult& result,
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_4::PhysicalCameraMetadata> &physicalCameraMetadata) {
+ processOneCaptureResultLockedT<HidlCaptureOutputStates,
+ hardware::camera::device::V3_2::CaptureResult,
+ hardware::hidl_vec<hardware::camera::device::V3_4::PhysicalCameraMetadata>,
+ hardware::hidl_vec<uint8_t>, ResultMetadataQueue,
+ hardware::camera::device::V3_2::BufferStatus>(states, result, physicalCameraMetadata);
+}
+
+void notify(CaptureOutputStates& states,
+ const hardware::camera::device::V3_8::NotifyMsg& msg) {
+ using android::hardware::camera::device::V3_2::MsgType;
+
+ hardware::camera::device::V3_2::NotifyMsg msg_3_2;
+ msg_3_2.type = msg.type;
+ bool hasReadoutTime = false;
+ uint64_t readoutTime = 0;
+ switch (msg.type) {
+ case MsgType::ERROR:
+ msg_3_2.msg.error = msg.msg.error;
+ break;
+ case MsgType::SHUTTER:
+ msg_3_2.msg.shutter = msg.msg.shutter.v3_2;
+ hasReadoutTime = true;
+ readoutTime = msg.msg.shutter.readoutTimestamp;
+ break;
+ }
+ notify(states, msg_3_2, hasReadoutTime, readoutTime);
+}
+
+void notify(CaptureOutputStates& states,
+ const hardware::camera::device::V3_2::NotifyMsg& msg,
+ bool hasReadoutTime, uint64_t readoutTime) {
+
+ using android::hardware::camera::device::V3_2::MsgType;
+ using android::hardware::camera::device::V3_2::ErrorCode;
+
+ ATRACE_CALL();
+ camera_notify_msg m;
+ switch (msg.type) {
+ case MsgType::ERROR:
+ m.type = CAMERA_MSG_ERROR;
+ m.message.error.frame_number = msg.msg.error.frameNumber;
+ if (msg.msg.error.errorStreamId >= 0) {
+ sp<Camera3StreamInterface> stream =
+ states.outputStreams.get(msg.msg.error.errorStreamId);
+ if (stream == nullptr) {
+ ALOGE("%s: Frame %d: Invalid error stream id %d", __FUNCTION__,
+ m.message.error.frame_number, msg.msg.error.errorStreamId);
+ return;
+ }
+ m.message.error.error_stream = stream->asHalStream();
+ } else {
+ m.message.error.error_stream = nullptr;
+ }
+ switch (msg.msg.error.errorCode) {
+ case ErrorCode::ERROR_DEVICE:
+ m.message.error.error_code = CAMERA_MSG_ERROR_DEVICE;
+ break;
+ case ErrorCode::ERROR_REQUEST:
+ m.message.error.error_code = CAMERA_MSG_ERROR_REQUEST;
+ break;
+ case ErrorCode::ERROR_RESULT:
+ m.message.error.error_code = CAMERA_MSG_ERROR_RESULT;
+ break;
+ case ErrorCode::ERROR_BUFFER:
+ m.message.error.error_code = CAMERA_MSG_ERROR_BUFFER;
+ break;
+ }
+ break;
+ case MsgType::SHUTTER:
+ m.type = CAMERA_MSG_SHUTTER;
+ m.message.shutter.frame_number = msg.msg.shutter.frameNumber;
+ m.message.shutter.timestamp = msg.msg.shutter.timestamp;
+ m.message.shutter.readout_timestamp = hasReadoutTime ?
+ readoutTime : m.message.shutter.timestamp;
+ break;
+ }
+ notify(states, &m);
+}
+
+
+
+// The buffers requested through this call are not tied to any CaptureRequest in
+// particular. They may used by the hal for a particular frame's output buffer
+// or for its internal use as well. In the case that the hal does use any buffer
+// from the requested list here, for a particular frame's output buffer, the
+// buffer will be returned with the processCaptureResult call corresponding to
+// the frame. The other buffers will be returned through returnStreamBuffers.
+// The buffers returned via returnStreamBuffers will not have a valid
+// timestamp(0) and will be dropped by the bufferqueue.
+void requestStreamBuffers(RequestBufferStates& states,
+ const hardware::hidl_vec<hardware::camera::device::V3_5::BufferRequest>& bufReqs,
+ hardware::camera::device::V3_5::ICameraDeviceCallback::requestStreamBuffers_cb _hidl_cb) {
+ using android::hardware::camera::device::V3_2::BufferStatus;
+ using android::hardware::camera::device::V3_2::StreamBuffer;
+ using android::hardware::camera::device::V3_5::BufferRequestStatus;
+ using android::hardware::camera::device::V3_5::StreamBufferRet;
+ using android::hardware::camera::device::V3_5::StreamBufferRequestError;
+
+ std::lock_guard<std::mutex> lock(states.reqBufferLock);
+
+ hardware::hidl_vec<StreamBufferRet> bufRets;
+ if (!states.useHalBufManager) {
+ ALOGE("%s: Camera %s does not support HAL buffer management",
+ __FUNCTION__, states.cameraId.string());
+ _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets);
+ return;
+ }
+
+ SortedVector<int32_t> streamIds;
+ ssize_t sz = streamIds.setCapacity(bufReqs.size());
+ if (sz < 0 || static_cast<size_t>(sz) != bufReqs.size()) {
+ ALOGE("%s: failed to allocate memory for %zu buffer requests",
+ __FUNCTION__, bufReqs.size());
+ _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets);
+ return;
+ }
+
+ if (bufReqs.size() > states.outputStreams.size()) {
+ ALOGE("%s: too many buffer requests (%zu > # of output streams %zu)",
+ __FUNCTION__, bufReqs.size(), states.outputStreams.size());
+ _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets);
+ return;
+ }
+
+ // Check for repeated streamId
+ for (const auto& bufReq : bufReqs) {
+ if (streamIds.indexOf(bufReq.streamId) != NAME_NOT_FOUND) {
+ ALOGE("%s: Stream %d appear multiple times in buffer requests",
+ __FUNCTION__, bufReq.streamId);
+ _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, bufRets);
+ return;
+ }
+ streamIds.add(bufReq.streamId);
+ }
+
+ if (!states.reqBufferIntf.startRequestBuffer()) {
+ ALOGE("%s: request buffer disallowed while camera service is configuring",
+ __FUNCTION__);
+ _hidl_cb(BufferRequestStatus::FAILED_CONFIGURING, bufRets);
+ return;
+ }
+
+ bufRets.resize(bufReqs.size());
+
+ bool allReqsSucceeds = true;
+ bool oneReqSucceeds = false;
+ for (size_t i = 0; i < bufReqs.size(); i++) {
+ const auto& bufReq = bufReqs[i];
+ auto& bufRet = bufRets[i];
+ int32_t streamId = bufReq.streamId;
+ sp<Camera3OutputStreamInterface> outputStream = states.outputStreams.get(streamId);
+ if (outputStream == nullptr) {
+ ALOGE("%s: Output stream id %d not found!", __FUNCTION__, streamId);
+ hardware::hidl_vec<StreamBufferRet> emptyBufRets;
+ _hidl_cb(BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS, emptyBufRets);
+ states.reqBufferIntf.endRequestBuffer();
+ return;
+ }
+
+ bufRet.streamId = streamId;
+ if (outputStream->isAbandoned()) {
+ bufRet.val.error(StreamBufferRequestError::STREAM_DISCONNECTED);
+ allReqsSucceeds = false;
+ continue;
+ }
+
+ size_t handOutBufferCount = outputStream->getOutstandingBuffersCount();
+ uint32_t numBuffersRequested = bufReq.numBuffersRequested;
+ size_t totalHandout = handOutBufferCount + numBuffersRequested;
+ uint32_t maxBuffers = outputStream->asHalStream()->max_buffers;
+ if (totalHandout > maxBuffers) {
+ // Not able to allocate enough buffer. Exit early for this stream
+ ALOGE("%s: request too much buffers for stream %d: at HAL: %zu + requesting: %d"
+ " > max: %d", __FUNCTION__, streamId, handOutBufferCount,
+ numBuffersRequested, maxBuffers);
+ bufRet.val.error(StreamBufferRequestError::MAX_BUFFER_EXCEEDED);
+ allReqsSucceeds = false;
+ continue;
+ }
+
+ hardware::hidl_vec<StreamBuffer> tmpRetBuffers(numBuffersRequested);
+ bool currentReqSucceeds = true;
+ std::vector<camera_stream_buffer_t> streamBuffers(numBuffersRequested);
+ std::vector<buffer_handle_t> newBuffers;
+ size_t numAllocatedBuffers = 0;
+ size_t numPushedInflightBuffers = 0;
+ for (size_t b = 0; b < numBuffersRequested; b++) {
+ camera_stream_buffer_t& sb = streamBuffers[b];
+ // Since this method can run concurrently with request thread
+ // We need to update the wait duration everytime we call getbuffer
+ nsecs_t waitDuration = states.reqBufferIntf.getWaitDuration();
+ status_t res = outputStream->getBuffer(&sb, waitDuration);
+ if (res != OK) {
+ if (res == NO_INIT || res == DEAD_OBJECT) {
+ ALOGV("%s: Can't get output buffer for stream %d: %s (%d)",
+ __FUNCTION__, streamId, strerror(-res), res);
+ bufRet.val.error(StreamBufferRequestError::STREAM_DISCONNECTED);
+ states.sessionStatsBuilder.stopCounter(streamId);
+ } else {
+ ALOGE("%s: Can't get output buffer for stream %d: %s (%d)",
+ __FUNCTION__, streamId, strerror(-res), res);
+ if (res == TIMED_OUT || res == NO_MEMORY) {
+ bufRet.val.error(StreamBufferRequestError::NO_BUFFER_AVAILABLE);
+ } else {
+ bufRet.val.error(StreamBufferRequestError::UNKNOWN_ERROR);
+ }
+ }
+ currentReqSucceeds = false;
+ break;
+ }
+ numAllocatedBuffers++;
+
+ buffer_handle_t *buffer = sb.buffer;
+ auto pair = states.bufferRecordsIntf.getBufferId(*buffer, streamId);
+ bool isNewBuffer = pair.first;
+ uint64_t bufferId = pair.second;
+ StreamBuffer& hBuf = tmpRetBuffers[b];
+
+ hBuf.streamId = streamId;
+ hBuf.bufferId = bufferId;
+ hBuf.buffer = (isNewBuffer) ? *buffer : nullptr;
+ hBuf.status = BufferStatus::OK;
+ hBuf.releaseFence = nullptr;
+ if (isNewBuffer) {
+ newBuffers.push_back(*buffer);
+ }
+
+ native_handle_t *acquireFence = nullptr;
+ if (sb.acquire_fence != -1) {
+ acquireFence = native_handle_create(1,0);
+ acquireFence->data[0] = sb.acquire_fence;
+ }
+ hBuf.acquireFence.setTo(acquireFence, /*shouldOwn*/true);
+ hBuf.releaseFence = nullptr;
+
+ res = states.bufferRecordsIntf.pushInflightRequestBuffer(bufferId, buffer, streamId);
+ if (res != OK) {
+ ALOGE("%s: Can't get register request buffers for stream %d: %s (%d)",
+ __FUNCTION__, streamId, strerror(-res), res);
+ bufRet.val.error(StreamBufferRequestError::UNKNOWN_ERROR);
+ currentReqSucceeds = false;
+ break;
+ }
+ numPushedInflightBuffers++;
+ }
+ if (currentReqSucceeds) {
+ bufRet.val.buffers(std::move(tmpRetBuffers));
+ oneReqSucceeds = true;
+ } else {
+ allReqsSucceeds = false;
+ for (size_t b = 0; b < numPushedInflightBuffers; b++) {
+ StreamBuffer& hBuf = tmpRetBuffers[b];
+ buffer_handle_t* buffer;
+ status_t res = states.bufferRecordsIntf.popInflightRequestBuffer(
+ hBuf.bufferId, &buffer);
+ if (res != OK) {
+ SET_ERR("%s: popInflightRequestBuffer failed for stream %d: %s (%d)",
+ __FUNCTION__, streamId, strerror(-res), res);
+ }
+ }
+ for (size_t b = 0; b < numAllocatedBuffers; b++) {
+ camera_stream_buffer_t& sb = streamBuffers[b];
+ sb.acquire_fence = -1;
+ sb.status = CAMERA_BUFFER_STATUS_ERROR;
+ }
+ returnOutputBuffers(states.useHalBufManager, /*listener*/nullptr,
+ streamBuffers.data(), numAllocatedBuffers, /*timestamp*/0,
+ /*readoutTimestamp*/0, /*requested*/false,
+ /*requestTimeNs*/0, states.sessionStatsBuilder);
+ for (auto buf : newBuffers) {
+ states.bufferRecordsIntf.removeOneBufferCache(streamId, buf);
+ }
+ }
+ }
+
+ _hidl_cb(allReqsSucceeds ? BufferRequestStatus::OK :
+ oneReqSucceeds ? BufferRequestStatus::FAILED_PARTIAL :
+ BufferRequestStatus::FAILED_UNKNOWN,
+ bufRets);
+ states.reqBufferIntf.endRequestBuffer();
+}
+
+void returnStreamBuffers(ReturnBufferStates& states,
+ const hardware::hidl_vec<hardware::camera::device::V3_2::StreamBuffer>& buffers) {
+ returnStreamBuffersT(states, buffers);
+}
+
+} // camera3
+} // namespace android
diff --git a/services/camera/libcameraservice/device3/hidl/HidlCamera3OutputUtils.h b/services/camera/libcameraservice/device3/hidl/HidlCamera3OutputUtils.h
new file mode 100644
index 0000000..583d738
--- /dev/null
+++ b/services/camera/libcameraservice/device3/hidl/HidlCamera3OutputUtils.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2022 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_SERVERS_HIDL_CAMERA3_OUTPUT_UTILS_H
+#define ANDROID_SERVERS_HIDL_CAMERA3_OUTPUT_UTILS_H
+
+#include <memory>
+#include <mutex>
+
+#include <cutils/native_handle.h>
+
+#include <fmq/MessageQueue.h>
+
+#include <common/CameraDeviceBase.h>
+
+#include <android/hardware/camera/device/3.8/ICameraDeviceCallback.h>
+
+#include "device3/BufferUtils.h"
+//#include "device3/DistortionMapper.h"
+//#include "device3/ZoomRatioMapper.h"
+//#include "device3/RotateAndCropMapper.h"
+#include "device3/InFlightRequest.h"
+#include "device3/Camera3Stream.h"
+//#include "device3/Camera3OutputStreamInterface.h"
+#include "device3/Camera3OutputUtils.h"
+//#include "utils/SessionStatsBuilder.h"
+//#include "utils/TagMonitor.h"
+
+namespace android {
+
+using ResultMetadataQueue = hardware::MessageQueue<uint8_t, hardware::kSynchronizedReadWrite>;
+
+namespace camera3 {
+
+ /**
+ * Helper methods shared between HidlCamera3Device/HidlCamera3OfflineSession for HAL callbacks
+ */
+ // Camera3Device/Camera3OfflineSession internal states used in notify/processCaptureResult
+ // callbacks
+ struct HidlCaptureOutputStates : public CaptureOutputStates {
+ std::unique_ptr<ResultMetadataQueue>& fmq;
+ };
+
+ // Handle one capture result. Assume callers hold the lock to serialize all
+ // processCaptureResult calls
+ void processOneCaptureResultLocked(
+ HidlCaptureOutputStates& states,
+ const hardware::camera::device::V3_2::CaptureResult& result,
+ const hardware::hidl_vec<
+ hardware::camera::device::V3_4::PhysicalCameraMetadata>
+ &physicalCameraMetadata);
+
+ // Handle one notify message
+ void notify(CaptureOutputStates& states,
+ const hardware::camera::device::V3_2::NotifyMsg& msg,
+ bool hasReadoutTime = false, uint64_t readoutTime = 0LL);
+ void notify(CaptureOutputStates& states,
+ const hardware::camera::device::V3_8::NotifyMsg& msg);
+
+ void requestStreamBuffers(RequestBufferStates& states,
+ const hardware::hidl_vec<hardware::camera::device::V3_5::BufferRequest>& bufReqs,
+ hardware::camera::device::V3_5::ICameraDeviceCallback::requestStreamBuffers_cb
+ _hidl_cb);
+ void returnStreamBuffers(ReturnBufferStates& states,
+ const hardware::hidl_vec<hardware::camera::device::V3_2::StreamBuffer>& buffers);
+
+} // namespace camera3
+
+} // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/hidl/AidlCameraServiceListener.cpp b/services/camera/libcameraservice/hidl/AidlCameraServiceListener.cpp
index 8e619e1..cca3f2e 100644
--- a/services/camera/libcameraservice/hidl/AidlCameraServiceListener.cpp
+++ b/services/camera/libcameraservice/hidl/AidlCameraServiceListener.cpp
@@ -70,6 +70,11 @@
return binder::Status::ok();
}
+::android::binder::Status H2BCameraServiceListener::onTorchStrengthLevelChanged(
+ const ::android::String16&, int32_t) {
+ return binder::Status::ok();
+}
+
} // implementation
} // V2_0
} // common
diff --git a/services/camera/libcameraservice/hidl/AidlCameraServiceListener.h b/services/camera/libcameraservice/hidl/AidlCameraServiceListener.h
index 7148035..7ef413f 100644
--- a/services/camera/libcameraservice/hidl/AidlCameraServiceListener.h
+++ b/services/camera/libcameraservice/hidl/AidlCameraServiceListener.h
@@ -54,6 +54,8 @@
virtual ::android::binder::Status onTorchStatusChanged(
int32_t status, const ::android::String16& cameraId) override;
+ virtual ::android::binder::Status onTorchStrengthLevelChanged(
+ const ::android::String16& cameraId, int32_t newStrengthLevel) override;
virtual binder::Status onCameraAccessPrioritiesChanged() {
// TODO: no implementation yet.
return binder::Status::ok();
diff --git a/services/camera/libcameraservice/libcameraservice_fuzzer/Android.bp b/services/camera/libcameraservice/libcameraservice_fuzzer/Android.bp
index 4f080fe..ca73e4c 100644
--- a/services/camera/libcameraservice/libcameraservice_fuzzer/Android.bp
+++ b/services/camera/libcameraservice/libcameraservice_fuzzer/Android.bp
@@ -59,6 +59,7 @@
"android.hardware.camera.device@3.5",
"android.hardware.camera.device@3.6",
"android.hardware.camera.device@3.7",
+ "android.hardware.camera.device@3.8",
],
fuzz_config: {
cc: [
diff --git a/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp b/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp
index e46bf74..97d7bf4 100644
--- a/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp
+++ b/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp
@@ -466,6 +466,12 @@
// No op
return binder::Status::ok();
}
+
+ virtual binder::Status onTorchStrengthLevelChanged(const String16& /*cameraId*/,
+ int32_t /*torchStrength*/) {
+ // No op
+ return binder::Status::ok();
+ }
};
class TestCameraDeviceCallbacks : public hardware::camera2::BnCameraDeviceCallbacks {
diff --git a/services/camera/libcameraservice/tests/Android.bp b/services/camera/libcameraservice/tests/Android.bp
index 5b8264c..c3f0620 100644
--- a/services/camera/libcameraservice/tests/Android.bp
+++ b/services/camera/libcameraservice/tests/Android.bp
@@ -48,6 +48,7 @@
"android.hardware.camera.device@3.2",
"android.hardware.camera.device@3.4",
"android.hardware.camera.device@3.7",
+ "android.hardware.camera.device@3.8",
"android.hidl.token@1.0-utils",
],
@@ -74,4 +75,51 @@
test_suites: ["device-tests"],
-}
\ No newline at end of file
+}
+
+cc_test_host {
+ name: "cameraservice_test_host",
+
+ include_dirs: [
+ "frameworks/av/camera/include",
+ "frameworks/av/camera/include/camera",
+ "frameworks/native/libs/binder/include_activitymanager"
+ ],
+
+ shared_libs: [
+ "libactivity_manager_procstate_aidl-cpp",
+ "libbase",
+ "libbinder",
+ "libcamera_metadata",
+ "libdynamic_depth",
+ "libexif",
+ "libjpeg",
+ "liblog",
+ "libutils",
+ ],
+
+ static_libs: [
+ "libcamera_client_host",
+ "libcameraservice_device_independent",
+ "libgmock",
+ ],
+
+ srcs: [
+ "ClientManagerTest.cpp",
+ "DepthProcessorTest.cpp",
+ "DistortionMapperTest.cpp",
+ "ExifUtilsTest.cpp",
+ "NV12Compressor.cpp",
+ "RotateAndCropMapperTest.cpp",
+ "ZoomRatioTest.cpp",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+
+ test_suites: ["device-tests"],
+
+}
diff --git a/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp b/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
index c8a6b32..e9f6979 100644
--- a/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
+++ b/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
@@ -212,7 +212,7 @@
* Simple test version of the interaction proxy, to use to inject onRegistered calls to the
* CameraProviderManager
*/
-struct TestInteractionProxy : public CameraProviderManager::ServiceInteractionProxy {
+struct TestInteractionProxy : public CameraProviderManager::HidlServiceInteractionProxy {
sp<hidl::manager::V1_0::IServiceNotification> mManagerNotificationInterface;
sp<TestICameraProvider> mTestCameraProvider;
@@ -269,13 +269,13 @@
~TestStatusListener() {}
void onDeviceStatusChanged(const String8 &,
- hardware::camera::common::V1_0::CameraDeviceStatus) override {}
+ CameraDeviceStatus) override {}
void onDeviceStatusChanged(const String8 &, const String8 &,
- hardware::camera::common::V1_0::CameraDeviceStatus) override {}
+ CameraDeviceStatus) override {}
void onTorchStatusChanged(const String8 &,
- hardware::camera::common::V1_0::TorchModeStatus) override {}
+ TorchModeStatus) override {}
void onTorchStatusChanged(const String8 &,
- hardware::camera::common::V1_0::TorchModeStatus, SystemCameraKind) override {}
+ TorchModeStatus, SystemCameraKind) override {}
void onNewProviderRegistered() override {}
};
diff --git a/services/camera/libcameraservice/tests/NV12Compressor.h b/services/camera/libcameraservice/tests/NV12Compressor.h
index ee22d5e..a959871 100644
--- a/services/camera/libcameraservice/tests/NV12Compressor.h
+++ b/services/camera/libcameraservice/tests/NV12Compressor.h
@@ -19,6 +19,7 @@
#include <setjmp.h>
#include <stdlib.h>
+#include <stdio.h>
extern "C" {
#include <jpeglib.h>
#include <jerror.h>
diff --git a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp
index 8d170f1..8699543 100644
--- a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp
+++ b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp
@@ -120,11 +120,12 @@
proxyBinder->pingForUserUpdate();
}
-int CameraServiceProxyWrapper::getRotateAndCropOverride(String16 packageName, int lensFacing) {
+int CameraServiceProxyWrapper::getRotateAndCropOverride(String16 packageName, int lensFacing,
+ int userId) {
sp<ICameraServiceProxy> proxyBinder = getCameraServiceProxy();
if (proxyBinder == nullptr) return true;
int ret = 0;
- auto status = proxyBinder->getRotateAndCropOverride(packageName, lensFacing, &ret);
+ auto status = proxyBinder->getRotateAndCropOverride(packageName, lensFacing, userId, &ret);
if (!status.isOk()) {
ALOGE("%s: Failed during top activity orientation query: %s", __FUNCTION__,
status.exceptionMessage().c_str());
diff --git a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.h b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.h
index a51e568..f701e94 100644
--- a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.h
+++ b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.h
@@ -92,7 +92,7 @@
static void pingCameraServiceProxy();
// Return the current top activity rotate and crop override.
- static int getRotateAndCropOverride(String16 packageName, int lensFacing);
+ static int getRotateAndCropOverride(String16 packageName, int lensFacing, int userId);
};
} // android
diff --git a/services/camera/libcameraservice/utils/IPCTransport.h b/services/camera/libcameraservice/utils/IPCTransport.h
new file mode 100644
index 0000000..b8e80ac
--- /dev/null
+++ b/services/camera/libcameraservice/utils/IPCTransport.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2022 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_SERVERS_IPC_H_
+#define ANDROID_SERVERS_IPC_H_
+
+enum class IPCTransport : uint32_t {
+ HIDL = 0,
+ AIDL = 1,
+ INVALID = 2
+};
+
+#endif
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
index a239c81..f826d83 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
@@ -13,71 +13,28 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
#include <cutils/properties.h>
#include "SessionConfigurationUtils.h"
#include "../api2/DepthCompositeStream.h"
#include "../api2/HeicCompositeStream.h"
+#include "android/hardware/camera/metadata/3.8/types.h"
#include "common/CameraDeviceBase.h"
#include "../CameraService.h"
-#include "device3/Camera3Device.h"
+#include "device3/hidl/HidlCamera3Device.h"
#include "device3/Camera3OutputStream.h"
+#include "system/graphics-base-v1.1.h"
using android::camera3::OutputStreamInfo;
using android::camera3::OutputStreamInfo;
using android::hardware::camera2::ICameraDeviceUser;
using android::hardware::camera::metadata::V3_6::CameraMetadataEnumAndroidSensorPixelMode;
+using android::hardware::camera::metadata::V3_8::CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap;
namespace android {
namespace camera3 {
-int32_t SessionConfigurationUtils::PERF_CLASS_LEVEL =
- property_get_int32("ro.odm.build.media_performance_class", 0);
-
-bool SessionConfigurationUtils::IS_PERF_CLASS = (PERF_CLASS_LEVEL == SDK_VERSION_S);
-
-camera3::Size SessionConfigurationUtils::getMaxJpegResolution(const CameraMetadata &metadata,
- bool ultraHighResolution) {
- int32_t maxJpegWidth = 0, maxJpegHeight = 0;
- const int STREAM_CONFIGURATION_SIZE = 4;
- const int STREAM_FORMAT_OFFSET = 0;
- const int STREAM_WIDTH_OFFSET = 1;
- const int STREAM_HEIGHT_OFFSET = 2;
- const int STREAM_IS_INPUT_OFFSET = 3;
-
- int32_t scalerSizesTag = ultraHighResolution ?
- ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION :
- ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS;
- camera_metadata_ro_entry_t availableStreamConfigs =
- metadata.find(scalerSizesTag);
- if (availableStreamConfigs.count == 0 ||
- availableStreamConfigs.count % STREAM_CONFIGURATION_SIZE != 0) {
- return camera3::Size(0, 0);
- }
-
- // Get max jpeg size (area-wise).
- for (size_t i= 0; i < availableStreamConfigs.count; i+= STREAM_CONFIGURATION_SIZE) {
- int32_t format = availableStreamConfigs.data.i32[i + STREAM_FORMAT_OFFSET];
- int32_t width = availableStreamConfigs.data.i32[i + STREAM_WIDTH_OFFSET];
- int32_t height = availableStreamConfigs.data.i32[i + STREAM_HEIGHT_OFFSET];
- int32_t isInput = availableStreamConfigs.data.i32[i + STREAM_IS_INPUT_OFFSET];
- if (isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT
- && format == HAL_PIXEL_FORMAT_BLOB &&
- (width * height > maxJpegWidth * maxJpegHeight)) {
- maxJpegWidth = width;
- maxJpegHeight = height;
- }
- }
-
- return camera3::Size(maxJpegWidth, maxJpegHeight);
-}
-
-size_t SessionConfigurationUtils::getUHRMaxJpegBufferSize(camera3::Size uhrMaxJpegSize,
- camera3::Size defaultMaxJpegSize, size_t defaultMaxJpegBufferSize) {
- return (uhrMaxJpegSize.width * uhrMaxJpegSize.height) /
- (defaultMaxJpegSize.width * defaultMaxJpegSize.height) * defaultMaxJpegBufferSize;
-}
-
void StreamConfiguration::getStreamConfigurations(
const CameraMetadata &staticInfo, int configuration,
std::unordered_map<int, std::vector<StreamConfiguration>> *scm) {
@@ -126,65 +83,57 @@
getStreamConfigurations(staticInfo, heicKey, scm);
}
-int32_t SessionConfigurationUtils::getAppropriateModeTag(int32_t defaultTag, bool maxResolution) {
- if (!maxResolution) {
- return defaultTag;
+namespace SessionConfigurationUtils {
+
+int32_t PERF_CLASS_LEVEL =
+ property_get_int32("ro.odm.build.media_performance_class", 0);
+
+bool IS_PERF_CLASS = (PERF_CLASS_LEVEL == SDK_VERSION_S);
+
+camera3::Size getMaxJpegResolution(const CameraMetadata &metadata,
+ bool ultraHighResolution) {
+ int32_t maxJpegWidth = 0, maxJpegHeight = 0;
+ const int STREAM_CONFIGURATION_SIZE = 4;
+ const int STREAM_FORMAT_OFFSET = 0;
+ const int STREAM_WIDTH_OFFSET = 1;
+ const int STREAM_HEIGHT_OFFSET = 2;
+ const int STREAM_IS_INPUT_OFFSET = 3;
+
+ int32_t scalerSizesTag = ultraHighResolution ?
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION :
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS;
+ camera_metadata_ro_entry_t availableStreamConfigs =
+ metadata.find(scalerSizesTag);
+ if (availableStreamConfigs.count == 0 ||
+ availableStreamConfigs.count % STREAM_CONFIGURATION_SIZE != 0) {
+ return camera3::Size(0, 0);
}
- switch (defaultTag) {
- case ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS:
- return ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION;
- case ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS:
- return ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION;
- case ANDROID_SCALER_AVAILABLE_STALL_DURATIONS:
- return ANDROID_SCALER_AVAILABLE_STALL_DURATIONS_MAXIMUM_RESOLUTION;
- case ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS:
- return ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION;
- case ANDROID_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS:
- return ANDROID_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION;
- case ANDROID_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS:
- return ANDROID_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS_MAXIMUM_RESOLUTION;
- case ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS:
- return ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION;
- case ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS:
- return ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION;
- case ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS:
- return ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS_MAXIMUM_RESOLUTION;
- case ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS:
- return ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION;
- case ANDROID_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS:
- return ANDROID_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION;
- case ANDROID_HEIC_AVAILABLE_HEIC_STALL_DURATIONS:
- return ANDROID_HEIC_AVAILABLE_HEIC_STALL_DURATIONS_MAXIMUM_RESOLUTION;
- case ANDROID_SENSOR_OPAQUE_RAW_SIZE:
- return ANDROID_SENSOR_OPAQUE_RAW_SIZE_MAXIMUM_RESOLUTION;
- case ANDROID_LENS_INTRINSIC_CALIBRATION:
- return ANDROID_LENS_INTRINSIC_CALIBRATION_MAXIMUM_RESOLUTION;
- case ANDROID_LENS_DISTORTION:
- return ANDROID_LENS_DISTORTION_MAXIMUM_RESOLUTION;
- default:
- ALOGE("%s: Tag %d doesn't have a maximum resolution counterpart", __FUNCTION__,
- defaultTag);
- return -1;
+
+ // Get max jpeg size (area-wise).
+ for (size_t i= 0; i < availableStreamConfigs.count; i+= STREAM_CONFIGURATION_SIZE) {
+ int32_t format = availableStreamConfigs.data.i32[i + STREAM_FORMAT_OFFSET];
+ int32_t width = availableStreamConfigs.data.i32[i + STREAM_WIDTH_OFFSET];
+ int32_t height = availableStreamConfigs.data.i32[i + STREAM_HEIGHT_OFFSET];
+ int32_t isInput = availableStreamConfigs.data.i32[i + STREAM_IS_INPUT_OFFSET];
+ if (isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT
+ && format == HAL_PIXEL_FORMAT_BLOB &&
+ (width * height > maxJpegWidth * maxJpegHeight)) {
+ maxJpegWidth = width;
+ maxJpegHeight = height;
+ }
}
- return -1;
+
+ return camera3::Size(maxJpegWidth, maxJpegHeight);
}
-bool SessionConfigurationUtils::getArrayWidthAndHeight(const CameraMetadata *deviceInfo,
- int32_t arrayTag, int32_t *width, int32_t *height) {
- if (width == nullptr || height == nullptr) {
- ALOGE("%s: width / height nullptr", __FUNCTION__);
- return false;
- }
- camera_metadata_ro_entry_t entry;
- entry = deviceInfo->find(arrayTag);
- if (entry.count != 4) return false;
- *width = entry.data.i32[2];
- *height = entry.data.i32[3];
- return true;
+size_t getUHRMaxJpegBufferSize(camera3::Size uhrMaxJpegSize,
+ camera3::Size defaultMaxJpegSize, size_t defaultMaxJpegBufferSize) {
+ return (uhrMaxJpegSize.width * uhrMaxJpegSize.height) /
+ (defaultMaxJpegSize.width * defaultMaxJpegSize.height) * defaultMaxJpegBufferSize;
}
StreamConfigurationPair
-SessionConfigurationUtils::getStreamConfigurationPair(const CameraMetadata &staticInfo) {
+getStreamConfigurationPair(const CameraMetadata &staticInfo) {
camera3::StreamConfigurationPair streamConfigurationPair;
camera3::StreamConfiguration::getStreamConfigurations(staticInfo, false,
&streamConfigurationPair.mDefaultStreamConfigurationMap);
@@ -193,13 +142,13 @@
return streamConfigurationPair;
}
-int64_t SessionConfigurationUtils::euclidDistSquare(int32_t x0, int32_t y0, int32_t x1, int32_t y1) {
+int64_t euclidDistSquare(int32_t x0, int32_t y0, int32_t x1, int32_t y1) {
int64_t d0 = x0 - x1;
int64_t d1 = y0 - y1;
return d0 * d0 + d1 * d1;
}
-bool SessionConfigurationUtils::roundBufferDimensionNearest(int32_t width, int32_t height,
+bool roundBufferDimensionNearest(int32_t width, int32_t height,
int32_t format, android_dataspace dataSpace,
const CameraMetadata& info, bool maxResolution, /*out*/int32_t* outWidth,
/*out*/int32_t* outHeight) {
@@ -260,7 +209,81 @@
return true;
}
-bool SessionConfigurationUtils::isPublicFormat(int32_t format)
+//check if format is 10-bit compatible
+bool is10bitCompatibleFormat(int32_t format) {
+ switch(format) {
+ case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
+ case HAL_PIXEL_FORMAT_YCBCR_P010:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool isDynamicRangeProfileSupported(int dynamicRangeProfile, const CameraMetadata& staticInfo) {
+ if (dynamicRangeProfile == ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD) {
+ // Supported by default
+ return true;
+ }
+
+ camera_metadata_ro_entry_t entry = staticInfo.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
+ bool is10bitDynamicRangeSupported = false;
+ for (size_t i = 0; i < entry.count; ++i) {
+ uint8_t capability = entry.data.u8[i];
+ if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT) {
+ is10bitDynamicRangeSupported = true;
+ break;
+ }
+ }
+
+ if (!is10bitDynamicRangeSupported) {
+ return false;
+ }
+
+ switch (dynamicRangeProfile) {
+ case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10_PLUS:
+ case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10:
+ case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HLG10:
+ case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM:
+ case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM_PO:
+ case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF:
+ case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF_PO:
+ case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM:
+ case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM_PO:
+ case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF:
+ case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF_PO:
+ entry = staticInfo.find(ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP);
+ for (size_t i = 0; i < entry.count; i += 2) {
+ if (dynamicRangeProfile == entry.data.i32[i]) {
+ return true;
+ }
+ }
+
+ return false;
+ default:
+ return false;
+ }
+
+ return false;
+}
+
+//check if format is 10-bit compatible
+bool is10bitDynamicRangeProfile(int32_t dynamicRangeProfile) {
+ switch (dynamicRangeProfile) {
+ case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10_PLUS:
+ case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10:
+ case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HLG10:
+ case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM:
+ case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM_PO:
+ case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF:
+ case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF_PO:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool isPublicFormat(int32_t format)
{
switch(format) {
case HAL_PIXEL_FORMAT_RGBA_8888:
@@ -287,11 +310,11 @@
}
}
-binder::Status SessionConfigurationUtils::createSurfaceFromGbp(
+binder::Status createSurfaceFromGbp(
OutputStreamInfo& streamInfo, bool isStreamInfoValid,
sp<Surface>& surface, const sp<IGraphicBufferProducer>& gbp,
const String8 &logicalCameraId, const CameraMetadata &physicalCameraMetadata,
- const std::vector<int32_t> &sensorPixelModesUsed){
+ const std::vector<int32_t> &sensorPixelModesUsed, int dynamicRangeProfile){
// bufferProducer must be non-null
if (gbp == nullptr) {
String8 msg = String8::format("Camera %s: Surface is NULL", logicalCameraId.string());
@@ -389,6 +412,21 @@
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
}
+ if (!SessionConfigurationUtils::isDynamicRangeProfileSupported(dynamicRangeProfile,
+ physicalCameraMetadata)) {
+ String8 msg = String8::format("Camera %s: Dynamic range profile 0x%x not supported,"
+ " failed to create output stream", logicalCameraId.string(), dynamicRangeProfile);
+ ALOGE("%s: %s", __FUNCTION__, msg.string());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+ }
+ if (SessionConfigurationUtils::is10bitDynamicRangeProfile(dynamicRangeProfile) &&
+ !SessionConfigurationUtils::is10bitCompatibleFormat(format)) {
+ String8 msg = String8::format("Camera %s: No 10-bit supported stream configurations with "
+ "format %#x defined and profile %#x, failed to create output stream",
+ logicalCameraId.string(), format, dynamicRangeProfile);
+ ALOGE("%s: %s", __FUNCTION__, msg.string());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+ }
if (!isStreamInfoValid) {
streamInfo.width = width;
@@ -397,6 +435,7 @@
streamInfo.dataSpace = dataSpace;
streamInfo.consumerUsage = consumerUsage;
streamInfo.sensorPixelModesUsed = overriddenSensorPixelModes;
+ streamInfo.dynamicRangeProfile = dynamicRangeProfile;
return binder::Status::ok();
}
if (width != streamInfo.width) {
@@ -437,35 +476,39 @@
return binder::Status::ok();
}
-void SessionConfigurationUtils::mapStreamInfo(const OutputStreamInfo &streamInfo,
+void mapStreamInfo(const OutputStreamInfo &streamInfo,
camera3::camera_stream_rotation_t rotation, String8 physicalId,
- int32_t groupId, hardware::camera::device::V3_7::Stream *stream /*out*/) {
+ int32_t groupId, hardware::camera::device::V3_8::Stream *stream /*out*/) {
if (stream == nullptr) {
return;
}
- 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);
+ stream->v3_7.v3_4.v3_2.streamType = hardware::camera::device::V3_2::StreamType::OUTPUT;
+ stream->v3_7.v3_4.v3_2.width = streamInfo.width;
+ stream->v3_7.v3_4.v3_2.height = streamInfo.height;
+ stream->v3_7.v3_4.v3_2.format = HidlCamera3Device::mapToPixelFormat(streamInfo.format);
auto u = streamInfo.consumerUsage;
camera3::Camera3OutputStream::applyZSLUsageQuirk(streamInfo.format, &u);
- 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;
- stream->sensorPixelModesUsed.resize(streamInfo.sensorPixelModesUsed.size());
+ stream->v3_7.v3_4.v3_2.usage = HidlCamera3Device::mapToConsumerUsage(u);
+ stream->v3_7.v3_4.v3_2.dataSpace = HidlCamera3Device::mapToHidlDataspace(streamInfo.dataSpace);
+ stream->v3_7.v3_4.v3_2.rotation = HidlCamera3Device::mapToStreamRotation(rotation);
+ stream->v3_7.v3_4.v3_2.id = -1; // Invalid stream id
+ stream->v3_7.v3_4.physicalCameraId = std::string(physicalId.string());
+ stream->v3_7.v3_4.bufferSize = 0;
+ stream->v3_7.groupId = groupId;
+ stream->v3_7.sensorPixelModesUsed.resize(streamInfo.sensorPixelModesUsed.size());
+
size_t idx = 0;
for (auto mode : streamInfo.sensorPixelModesUsed) {
- stream->sensorPixelModesUsed[idx++] =
+ stream->v3_7.sensorPixelModesUsed[idx++] =
static_cast<CameraMetadataEnumAndroidSensorPixelMode>(mode);
}
+ stream->dynamicRangeProfile =
+ static_cast<CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap> (
+ streamInfo.dynamicRangeProfile);
}
-binder::Status SessionConfigurationUtils::checkPhysicalCameraId(
+binder::Status checkPhysicalCameraId(
const std::vector<std::string> &physicalCameraIds, const String8 &physicalCameraId,
const String8 &logicalCameraId) {
if (physicalCameraId.size() == 0) {
@@ -481,7 +524,7 @@
return binder::Status::ok();
}
-binder::Status SessionConfigurationUtils::checkSurfaceType(size_t numBufferProducers,
+binder::Status checkSurfaceType(size_t numBufferProducers,
bool deferredConsumer, int surfaceType) {
if (numBufferProducers > MAX_SURFACES_PER_STREAM) {
ALOGE("%s: GraphicBufferProducer count %zu for stream exceeds limit of %d",
@@ -503,7 +546,7 @@
return binder::Status::ok();
}
-binder::Status SessionConfigurationUtils::checkOperatingMode(int operatingMode,
+binder::Status checkOperatingMode(int operatingMode,
const CameraMetadata &staticInfo, const String8 &cameraId) {
if (operatingMode < 0) {
String8 msg = String8::format(
@@ -538,11 +581,11 @@
}
binder::Status
-SessionConfigurationUtils::convertToHALStreamCombination(
+convertToHALStreamCombination(
const SessionConfiguration& sessionConfiguration,
const String8 &logicalCameraId, const CameraMetadata &deviceInfo,
metadataGetter getMetadata, const std::vector<std::string> &physicalCameraIds,
- hardware::camera::device::V3_7::StreamConfiguration &streamConfiguration,
+ hardware::camera::device::V3_8::StreamConfiguration &streamConfiguration,
bool overrideForPerfClass, bool *earlyExit) {
auto operatingMode = sessionConfiguration.getOperatingMode();
@@ -557,7 +600,7 @@
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
}
*earlyExit = false;
- auto ret = Camera3Device::mapToStreamConfigurationMode(
+ auto ret = HidlCamera3Device::mapToStreamConfigurationMode(
static_cast<camera_stream_configuration_mode_t> (operatingMode),
/*out*/ &streamConfiguration.operationMode);
if (ret != OK) {
@@ -583,11 +626,11 @@
defaultSensorPixelModes[0] =
static_cast<CameraMetadataEnumAndroidSensorPixelMode>(
ANDROID_SENSOR_PIXEL_MODE_DEFAULT);
- streamConfiguration.streams[streamIdx++] = {{{/*streamId*/0,
+ streamConfiguration.streams[streamIdx++].v3_7 = {{{/*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()),
+ HidlCamera3Device::mapToPixelFormat(sessionConfiguration.getInputFormat()),
/*usage*/ 0, HAL_DATASPACE_UNKNOWN,
hardware::camera::device::V3_2::StreamRotation::ROTATION_0},
/*physicalId*/ nullptr, /*bufferSize*/0}, /*groupId*/-1, defaultSensorPixelModes};
@@ -601,6 +644,7 @@
bool deferredConsumer = it.isDeferred();
String8 physicalCameraId = String8(it.getPhysicalCameraId());
+ int dynamicRangeProfile = it.getDynamicRangeProfile();
std::vector<int32_t> sensorPixelModesUsed = it.getSensorPixelModesUsed();
const CameraMetadata &physicalDeviceInfo = getMetadata(physicalCameraId,
overrideForPerfClass);
@@ -632,6 +676,7 @@
if (surfaceType == OutputConfiguration::SURFACE_TYPE_SURFACE_VIEW) {
streamInfo.consumerUsage |= GraphicBuffer::USAGE_HW_COMPOSER;
}
+ streamInfo.dynamicRangeProfile = it.getDynamicRangeProfile();
if (checkAndOverrideSensorPixelModesUsed(sensorPixelModesUsed,
streamInfo.format, streamInfo.width,
streamInfo.height, metadataChosen, false /*flexibleConsumer*/,
@@ -653,7 +698,7 @@
for (auto& bufferProducer : bufferProducers) {
sp<Surface> surface;
res = createSurfaceFromGbp(streamInfo, isStreamInfoValid, surface, bufferProducer,
- logicalCameraId, metadataChosen, sensorPixelModesUsed);
+ logicalCameraId, metadataChosen, sensorPixelModesUsed, dynamicRangeProfile);
if (!res.isOk())
return res;
@@ -729,7 +774,7 @@
return std::unordered_set<int32_t>(sensorPixelModesUsed.begin(), sensorPixelModesUsed.end());
}
-status_t SessionConfigurationUtils::checkAndOverrideSensorPixelModesUsed(
+status_t checkAndOverrideSensorPixelModesUsed(
const std::vector<int32_t> &sensorPixelModesUsed, int format, int width, int height,
const CameraMetadata &staticInfo, bool flexibleConsumer,
std::unordered_set<int32_t> *overriddenSensorPixelModesUsed) {
@@ -795,21 +840,26 @@
return OK;
}
-bool SessionConfigurationUtils::isUltraHighResolutionSensor(const CameraMetadata &deviceInfo) {
- camera_metadata_ro_entry_t entryCap;
- entryCap = deviceInfo.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
- // Go through the capabilities and check if it has
- // ANDROID_REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR
- for (size_t i = 0; i < entryCap.count; ++i) {
- uint8_t capability = entryCap.data.u8[i];
- if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR) {
- return true;
+bool convertHALStreamCombinationFromV38ToV37(
+ hardware::camera::device::V3_7::StreamConfiguration &streamConfigV37,
+ const hardware::camera::device::V3_8::StreamConfiguration &streamConfigV38) {
+ streamConfigV37.streams.resize(streamConfigV38.streams.size());
+ for (size_t i = 0; i < streamConfigV38.streams.size(); i++) {
+ if (static_cast<int32_t>(streamConfigV38.streams[i].dynamicRangeProfile) !=
+ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD) {
+ // ICameraDevice older than 3.8 doesn't support 10-bit dynamic range profiles
+ // image
+ return false;
}
+ streamConfigV37.streams[i] = streamConfigV38.streams[i].v3_7;
}
- return false;
+ streamConfigV37.operationMode = streamConfigV38.operationMode;
+ streamConfigV37.sessionParams = streamConfigV38.sessionParams;
+
+ return true;
}
-bool SessionConfigurationUtils::convertHALStreamCombinationFromV37ToV34(
+bool convertHALStreamCombinationFromV37ToV34(
hardware::camera::device::V3_4::StreamConfiguration &streamConfigV34,
const hardware::camera::device::V3_7::StreamConfiguration &streamConfigV37) {
if (streamConfigV37.multiResolutionInputImage) {
@@ -832,7 +882,7 @@
return true;
}
-bool SessionConfigurationUtils::targetPerfClassPrimaryCamera(
+bool targetPerfClassPrimaryCamera(
const std::set<std::string>& perfClassPrimaryCameraIds, const std::string& cameraId,
int targetSdkVersion) {
bool isPerfClassPrimaryCamera =
@@ -840,5 +890,6 @@
return targetSdkVersion >= SDK_VERSION_S && isPerfClassPrimaryCamera;
}
+} // namespace SessionConfigurationUtils
} // namespace camera3
} // namespace android
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.h b/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
index 1053327..9a5dc2c 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
@@ -24,12 +24,15 @@
#include <android/hardware/camera/device/3.8/types.h>
#include <android/hardware/camera/device/3.4/ICameraDeviceSession.h>
#include <android/hardware/camera/device/3.7/ICameraDeviceSession.h>
+#include <android/hardware/camera/device/3.8/ICameraDeviceSession.h>
#include <device3/Camera3StreamInterface.h>
#include <set>
#include <stdint.h>
+#include "SessionConfigurationUtilsHost.h"
+
// Convenience methods for constructing binder::Status objects for error returns
#define STATUS_ERROR(errorCode, errorString) \
@@ -69,96 +72,105 @@
mMaximumResolutionStreamConfigurationMap;
};
-class SessionConfigurationUtils {
-public:
- static camera3::Size getMaxJpegResolution(const CameraMetadata &metadata,
- bool ultraHighResolution);
+namespace SessionConfigurationUtils {
- static size_t getUHRMaxJpegBufferSize(camera3::Size uhrMaxJpegSize,
- camera3::Size defaultMaxJpegSize, size_t defaultMaxJpegBufferSize);
+camera3::Size getMaxJpegResolution(const CameraMetadata &metadata,
+ bool ultraHighResolution);
- static int64_t euclidDistSquare(int32_t x0, int32_t y0, int32_t x1, int32_t y1);
+size_t getUHRMaxJpegBufferSize(camera3::Size uhrMaxJpegSize,
+ camera3::Size defaultMaxJpegSize, size_t defaultMaxJpegBufferSize);
- // Find the closest dimensions for a given format in available stream configurations with
- // a width <= ROUNDING_WIDTH_CAP
- static bool roundBufferDimensionNearest(int32_t width, int32_t height, int32_t format,
- android_dataspace dataSpace, const CameraMetadata& info, bool maxResolution,
- /*out*/int32_t* outWidth, /*out*/int32_t* outHeight);
+int64_t euclidDistSquare(int32_t x0, int32_t y0, int32_t x1, int32_t y1);
- static bool getArrayWidthAndHeight(const CameraMetadata *deviceInfo, int32_t arrayTag,
- int32_t *width, int32_t *height);
+// Find the closest dimensions for a given format in available stream configurations with
+// a width <= ROUNDING_WIDTH_CAP
+bool roundBufferDimensionNearest(int32_t width, int32_t height, int32_t format,
+ android_dataspace dataSpace, const CameraMetadata& info, bool maxResolution,
+ /*out*/int32_t* outWidth, /*out*/int32_t* outHeight);
- //check if format is not custom format
- static bool isPublicFormat(int32_t format);
+// check if format is not custom format
+bool isPublicFormat(int32_t format);
- // Create a Surface from an IGraphicBufferProducer. Returns error if
- // IGraphicBufferProducer's property doesn't match with streamInfo
- static binder::Status createSurfaceFromGbp(
- camera3::OutputStreamInfo& streamInfo, bool isStreamInfoValid,
- sp<Surface>& surface, const sp<IGraphicBufferProducer>& gbp,
- const String8 &logicalCameraId, const CameraMetadata &physicalCameraMetadata,
- const std::vector<int32_t> &sensorPixelModesUsed);
+// Create a Surface from an IGraphicBufferProducer. Returns error if
+// IGraphicBufferProducer's property doesn't match with streamInfo
+binder::Status createSurfaceFromGbp(
+camera3::OutputStreamInfo& streamInfo, bool isStreamInfoValid,
+sp<Surface>& surface, const sp<IGraphicBufferProducer>& gbp,
+const String8 &logicalCameraId, const CameraMetadata &physicalCameraMetadata,
+const std::vector<int32_t> &sensorPixelModesUsed, int dynamicRangeProfile);
+void mapStreamInfo(const camera3::OutputStreamInfo &streamInfo,
+ camera3::camera_stream_rotation_t rotation, String8 physicalId, int32_t groupId,
+ hardware::camera::device::V3_7::Stream *stream /*out*/);
- static void mapStreamInfo(const camera3::OutputStreamInfo &streamInfo,
- camera3::camera_stream_rotation_t rotation, String8 physicalId, int32_t groupId,
- hardware::camera::device::V3_7::Stream *stream /*out*/);
+//check if format is 10-bit output compatible
+bool is10bitCompatibleFormat(int32_t format);
- // Check that the physicalCameraId passed in is spported by the camera
- // device.
- static binder::Status checkPhysicalCameraId(
- const std::vector<std::string> &physicalCameraIds, const String8 &physicalCameraId,
- const String8 &logicalCameraId);
+// check if the dynamic range requires 10-bit output
+bool is10bitDynamicRangeProfile(int32_t dynamicRangeProfile);
- static binder::Status checkSurfaceType(size_t numBufferProducers,
- bool deferredConsumer, int surfaceType);
+// Check if the device supports a given dynamicRangeProfile
+bool isDynamicRangeProfileSupported(int dynamicRangeProfile, const CameraMetadata& staticMeta);
- static binder::Status checkOperatingMode(int operatingMode,
- const CameraMetadata &staticInfo, const String8 &cameraId);
+// Check that the physicalCameraId passed in is spported by the camera
+// device.
+binder::Status checkPhysicalCameraId(
+const std::vector<std::string> &physicalCameraIds, const String8 &physicalCameraId,
+const String8 &logicalCameraId);
- // utility function to convert AIDL SessionConfiguration to HIDL
- // streamConfiguration. Also checks for validity of SessionConfiguration and
- // returns a non-ok binder::Status if the passed in session configuration
- // isn't valid.
- static binder::Status
- convertToHALStreamCombination(const SessionConfiguration& sessionConfiguration,
- const String8 &cameraId, const CameraMetadata &deviceInfo,
- metadataGetter getMetadata, const std::vector<std::string> &physicalCameraIds,
- hardware::camera::device::V3_7::StreamConfiguration &streamConfiguration,
- bool overrideForPerfClass, bool *earlyExit);
+binder::Status checkSurfaceType(size_t numBufferProducers,
+bool deferredConsumer, int surfaceType);
- // 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);
+binder::Status checkOperatingMode(int operatingMode,
+const CameraMetadata &staticInfo, const String8 &cameraId);
- static StreamConfigurationPair getStreamConfigurationPair(const CameraMetadata &metadata);
+// utility function to convert AIDL SessionConfiguration to HIDL
+// streamConfiguration. Also checks for validity of SessionConfiguration and
+// returns a non-ok binder::Status if the passed in session configuration
+// isn't valid.
+binder::Status
+convertToHALStreamCombination(const SessionConfiguration& sessionConfiguration,
+ const String8 &cameraId, const CameraMetadata &deviceInfo,
+ metadataGetter getMetadata, const std::vector<std::string> &physicalCameraIds,
+ hardware::camera::device::V3_8::StreamConfiguration &streamConfiguration,
+ bool overrideForPerfClass, bool *earlyExit);
- static status_t checkAndOverrideSensorPixelModesUsed(
- const std::vector<int32_t> &sensorPixelModesUsed, int format, int width, int height,
- const CameraMetadata &staticInfo, bool flexibleConsumer,
- std::unordered_set<int32_t> *overriddenSensorPixelModesUsed);
+// Utility function to convert a V3_8::StreamConfiguration to
+// V3_7::StreamConfiguration. Return false if the original V3_8 configuration cannot
+// be used by older version HAL.
+bool convertHALStreamCombinationFromV38ToV37(
+ hardware::camera::device::V3_7::StreamConfiguration &streamConfigV37,
+ const hardware::camera::device::V3_8::StreamConfiguration &streamConfigV38);
- static bool isUltraHighResolutionSensor(const CameraMetadata &deviceInfo);
+// 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.
+bool convertHALStreamCombinationFromV37ToV34(
+ hardware::camera::device::V3_4::StreamConfiguration &streamConfigV34,
+ const hardware::camera::device::V3_7::StreamConfiguration &streamConfigV37);
- static int32_t getAppropriateModeTag(int32_t defaultTag, bool maxResolution = false);
+StreamConfigurationPair getStreamConfigurationPair(const CameraMetadata &metadata);
- static bool targetPerfClassPrimaryCamera(
- const std::set<std::string>& perfClassPrimaryCameraIds, const std::string& cameraId,
- int32_t targetSdkVersion);
+status_t checkAndOverrideSensorPixelModesUsed(
+ const std::vector<int32_t> &sensorPixelModesUsed, int format, int width, int height,
+ const CameraMetadata &staticInfo, bool flexibleConsumer,
+ std::unordered_set<int32_t> *overriddenSensorPixelModesUsed);
- static const int32_t MAX_SURFACES_PER_STREAM = 4;
+bool targetPerfClassPrimaryCamera(
+ const std::set<std::string>& perfClassPrimaryCameraIds, const std::string& cameraId,
+ int32_t targetSdkVersion);
- static const int32_t ROUNDING_WIDTH_CAP = 1920;
+constexpr int32_t MAX_SURFACES_PER_STREAM = 4;
- static const int32_t SDK_VERSION_S = 31;
- static int32_t PERF_CLASS_LEVEL;
- static bool IS_PERF_CLASS;
- static const int32_t PERF_CLASS_JPEG_THRESH_W = 1920;
- static const int32_t PERF_CLASS_JPEG_THRESH_H = 1080;
-};
+constexpr int32_t ROUNDING_WIDTH_CAP = 1920;
+constexpr int32_t SDK_VERSION_S = 31;
+extern int32_t PERF_CLASS_LEVEL;
+extern bool IS_PERF_CLASS;
+constexpr int32_t PERF_CLASS_JPEG_THRESH_W = 1920;
+constexpr int32_t PERF_CLASS_JPEG_THRESH_H = 1080;
+
+} // SessionConfigurationUtils
} // camera3
} // android
+
#endif
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtilsHost.cpp b/services/camera/libcameraservice/utils/SessionConfigurationUtilsHost.cpp
new file mode 100644
index 0000000..1efdc60
--- /dev/null
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtilsHost.cpp
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+
+#include "SessionConfigurationUtilsHost.h"
+
+namespace android {
+namespace camera3 {
+namespace SessionConfigurationUtils {
+
+int32_t getAppropriateModeTag(int32_t defaultTag, bool maxResolution) {
+ if (!maxResolution) {
+ return defaultTag;
+ }
+ switch (defaultTag) {
+ case ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS:
+ return ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION;
+ case ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS:
+ return ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION;
+ case ANDROID_SCALER_AVAILABLE_STALL_DURATIONS:
+ return ANDROID_SCALER_AVAILABLE_STALL_DURATIONS_MAXIMUM_RESOLUTION;
+ case ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS:
+ return ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION;
+ case ANDROID_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS:
+ return ANDROID_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION;
+ case ANDROID_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS:
+ return ANDROID_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS_MAXIMUM_RESOLUTION;
+ case ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS:
+ return ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION;
+ case ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS:
+ return ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION;
+ case ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS:
+ return ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS_MAXIMUM_RESOLUTION;
+ case ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS:
+ return ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION;
+ case ANDROID_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS:
+ return ANDROID_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION;
+ case ANDROID_HEIC_AVAILABLE_HEIC_STALL_DURATIONS:
+ return ANDROID_HEIC_AVAILABLE_HEIC_STALL_DURATIONS_MAXIMUM_RESOLUTION;
+ case ANDROID_SENSOR_OPAQUE_RAW_SIZE:
+ return ANDROID_SENSOR_OPAQUE_RAW_SIZE_MAXIMUM_RESOLUTION;
+ case ANDROID_LENS_INTRINSIC_CALIBRATION:
+ return ANDROID_LENS_INTRINSIC_CALIBRATION_MAXIMUM_RESOLUTION;
+ case ANDROID_LENS_DISTORTION:
+ return ANDROID_LENS_DISTORTION_MAXIMUM_RESOLUTION;
+ default:
+ ALOGE("%s: Tag %d doesn't have a maximum resolution counterpart", __FUNCTION__,
+ defaultTag);
+ return -1;
+ }
+ return -1;
+}
+
+bool isUltraHighResolutionSensor(const CameraMetadata &deviceInfo) {
+ camera_metadata_ro_entry_t entryCap;
+ entryCap = deviceInfo.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
+ // Go through the capabilities and check if it has
+ // ANDROID_REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR
+ for (size_t i = 0; i < entryCap.count; ++i) {
+ uint8_t capability = entryCap.data.u8[i];
+ if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool getArrayWidthAndHeight(const CameraMetadata *deviceInfo,
+ int32_t arrayTag, int32_t *width, int32_t *height) {
+ if (width == nullptr || height == nullptr) {
+ ALOGE("%s: width / height nullptr", __FUNCTION__);
+ return false;
+ }
+ camera_metadata_ro_entry_t entry;
+ entry = deviceInfo->find(arrayTag);
+ if (entry.count != 4) return false;
+ *width = entry.data.i32[2];
+ *height = entry.data.i32[3];
+ return true;
+}
+
+} // namespace SessionConfigurationUtils
+} // namespace camera3
+} // namespace android
\ No newline at end of file
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtilsHost.h b/services/camera/libcameraservice/utils/SessionConfigurationUtilsHost.h
new file mode 100644
index 0000000..45b1e91
--- /dev/null
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtilsHost.h
@@ -0,0 +1,36 @@
+/*
+ * 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_SERVERS_CAMERA_SESSION_CONFIGURATION_UTILS_HOST_H
+#define ANDROID_SERVERS_CAMERA_SESSION_CONFIGURATION_UTILS_HOST_H
+
+#include "camera/CameraMetadata.h"
+
+namespace android {
+namespace camera3 {
+namespace SessionConfigurationUtils {
+
+bool isUltraHighResolutionSensor(const CameraMetadata &deviceInfo);
+
+int32_t getAppropriateModeTag(int32_t defaultTag, bool maxResolution = false);
+
+bool getArrayWidthAndHeight(const CameraMetadata *deviceInfo, int32_t arrayTag,
+ int32_t *width, int32_t *height);
+
+} // SessionConfigurationUtils
+} // camera3
+} // android
+
+#endif
\ No newline at end of file
diff --git a/services/mediametrics/Android.bp b/services/mediametrics/Android.bp
index 74e4715..11534bb 100644
--- a/services/mediametrics/Android.bp
+++ b/services/mediametrics/Android.bp
@@ -181,11 +181,22 @@
"libstatssocket",
],
+ // within the library, we use "xxx.h"
+ local_include_dirs: [
+ "include/mediametricsservice",
+ ],
+
+ // external parties use <mediametricsservice/xxx.h>
+ export_include_dirs: [
+ "include",
+ ],
+
static_libs: [
"libplatformprotos",
],
- include_dirs: [
- "system/media/audio_utils/include",
+ header_libs: [
+ "libaaudio_headers",
+ "libaudioutils_headers",
],
}
diff --git a/services/mediametrics/AudioAnalytics.cpp b/services/mediametrics/AudioAnalytics.cpp
index 270fe2f..0e4dfcf 100644
--- a/services/mediametrics/AudioAnalytics.cpp
+++ b/services/mediametrics/AudioAnalytics.cpp
@@ -21,6 +21,7 @@
#include "AudioAnalytics.h"
+#include <aaudio/AAudio.h> // error codes
#include <audio_utils/clock.h> // clock conversions
#include <cutils/properties.h>
#include <statslog.h> // statsd
@@ -64,6 +65,50 @@
}
}
+// The status variable contains status_t codes which are used by
+// the core audio framework. We also consider AAudio status codes.
+//
+// Compare with mediametrics::statusToStatusString
+//
+inline constexpr const char* extendedStatusToStatusString(status_t status) {
+ switch (status) {
+ case BAD_VALUE: // status_t
+ case AAUDIO_ERROR_ILLEGAL_ARGUMENT:
+ case AAUDIO_ERROR_INVALID_FORMAT:
+ case AAUDIO_ERROR_INVALID_RATE:
+ case AAUDIO_ERROR_NULL:
+ case AAUDIO_ERROR_OUT_OF_RANGE:
+ return AMEDIAMETRICS_PROP_STATUS_VALUE_ARGUMENT;
+ case DEAD_OBJECT: // status_t
+ case FAILED_TRANSACTION: // status_t
+ case AAUDIO_ERROR_DISCONNECTED:
+ case AAUDIO_ERROR_INVALID_HANDLE:
+ case AAUDIO_ERROR_NO_SERVICE:
+ return AMEDIAMETRICS_PROP_STATUS_VALUE_IO;
+ case NO_MEMORY: // status_t
+ case AAUDIO_ERROR_NO_FREE_HANDLES:
+ case AAUDIO_ERROR_NO_MEMORY:
+ return AMEDIAMETRICS_PROP_STATUS_VALUE_MEMORY;
+ case PERMISSION_DENIED: // status_t
+ return AMEDIAMETRICS_PROP_STATUS_VALUE_SECURITY;
+ case INVALID_OPERATION: // status_t
+ case NO_INIT: // status_t
+ case AAUDIO_ERROR_INVALID_STATE:
+ case AAUDIO_ERROR_UNAVAILABLE:
+ case AAUDIO_ERROR_UNIMPLEMENTED:
+ return AMEDIAMETRICS_PROP_STATUS_VALUE_STATE;
+ case WOULD_BLOCK: // status_t
+ case AAUDIO_ERROR_TIMEOUT:
+ case AAUDIO_ERROR_WOULD_BLOCK:
+ return AMEDIAMETRICS_PROP_STATUS_VALUE_TIMEOUT;
+ default:
+ if (status >= 0) return AMEDIAMETRICS_PROP_STATUS_VALUE_OK; // non-negative values "OK"
+ [[fallthrough]]; // negative values are error.
+ case UNKNOWN_ERROR: // status_t
+ return AMEDIAMETRICS_PROP_STATUS_VALUE_UNKNOWN;
+ }
+}
+
static constexpr const auto LOG_LEVEL = android::base::VERBOSE;
static constexpr int PREVIOUS_STATE_EXPIRE_SEC = 60 * 60; // 1 hour.
@@ -130,6 +175,24 @@
"log_session_id",
};
+static constexpr const char * const AudioTrackStatusFields[] {
+ "mediametrics_audiotrackstatus_reported",
+ "status",
+ "debug_message",
+ "sub_code",
+ "uid",
+ "event",
+ "flags",
+ "content_type",
+ "usage",
+ "encoding",
+ "channel_mask",
+ "buffer_frame_count",
+ "sample_rate",
+ "speed",
+ "pitch",
+};
+
static constexpr const char * const AudioDeviceConnectionFields[] = {
"mediametrics_audiodeviceconnection_reported",
"input_devices",
@@ -392,11 +455,15 @@
{
if (!startsWith(item->getKey(), AMEDIAMETRICS_KEY_PREFIX_AUDIO)) return BAD_VALUE;
status_t status = mAnalyticsState->submit(item, isTrusted);
+
+ // Status is selectively authenticated.
+ processStatus(item);
+
if (status != NO_ERROR) return status; // may not be permitted.
// Only if the item was successfully submitted (permission)
// do we check triggered actions.
- checkActions(item);
+ processActions(item);
return NO_ERROR;
}
@@ -430,7 +497,7 @@
return { ss.str(), lines - ll };
}
-void AudioAnalytics::checkActions(const std::shared_ptr<const mediametrics::Item>& item)
+void AudioAnalytics::processActions(const std::shared_ptr<const mediametrics::Item>& item)
{
auto actions = mActions.getActionsForItem(item); // internally locked.
// Execute actions with no lock held.
@@ -439,6 +506,116 @@
}
}
+void AudioAnalytics::processStatus(const std::shared_ptr<const mediametrics::Item>& item)
+{
+ int32_t status;
+ if (!item->get(AMEDIAMETRICS_PROP_STATUS, &status)) return;
+
+ // Any record with a status will automatically be added to a heat map.
+ // Standard information.
+ const auto key = item->getKey();
+ const auto uid = item->getUid();
+
+ // from audio.track.10 -> prefix = audio.track, suffix = 10
+ // from audio.track.error -> prefix = audio.track, suffix = error
+ const auto [prefixKey, suffixKey] = stringutils::splitPrefixKey(key);
+
+ std::string message;
+ item->get(AMEDIAMETRICS_PROP_STATUSMESSAGE, &message); // optional
+
+ int32_t subCode = 0; // not used
+ (void)item->get(AMEDIAMETRICS_PROP_STATUSSUBCODE, &subCode); // optional
+
+ std::string eventStr; // optional
+ item->get(AMEDIAMETRICS_PROP_EVENT, &eventStr);
+
+ const std::string statusString = extendedStatusToStatusString(status);
+
+ // Add to the heat map - we automatically track every item's status to see
+ // the types of errors and the frequency of errors.
+ mHeatMap.add(prefixKey, suffixKey, eventStr, statusString, uid, message, subCode);
+
+ // Certain keys/event pairs are sent to statsd.
+ // Note that the prefixes often end with a '.' so we use startsWith.
+ if (startsWith(key, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)
+ && eventStr == AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE) {
+ const int atom_status = types::lookup<types::STATUS, int32_t>(statusString);
+
+ // currently we only send create status events.
+ const int32_t event =
+ android::util::MEDIAMETRICS_AUDIO_TRACK_STATUS_REPORTED__EVENT__EVENT_CREATE;
+
+ // The following fields should all be present in a create event.
+ std::string flagsStr;
+ ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_ORIGINALFLAGS, &flagsStr),
+ "%s: %s missing %s field",
+ __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_ORIGINALFLAGS);
+ const auto flags = types::lookup<types::OUTPUT_FLAG, int32_t>(flagsStr);
+
+ // AMEDIAMETRICS_PROP_SESSIONID omitted from atom
+
+ std::string contentTypeStr;
+ ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_CONTENTTYPE, &contentTypeStr),
+ "%s: %s missing %s field",
+ __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_CONTENTTYPE);
+ const auto contentType = types::lookup<types::CONTENT_TYPE, int32_t>(contentTypeStr);
+
+ std::string usageStr;
+ ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_USAGE, &usageStr),
+ "%s: %s missing %s field",
+ __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_USAGE);
+ const auto usage = types::lookup<types::USAGE, int32_t>(usageStr);
+
+ // AMEDIAMETRICS_PROP_SELECTEDDEVICEID omitted from atom
+
+ std::string encodingStr;
+ ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_ENCODING, &encodingStr),
+ "%s: %s missing %s field",
+ __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_ENCODING);
+ const auto encoding = types::lookup<types::ENCODING, int32_t>(encodingStr);
+
+ int32_t channelMask = 0;
+ ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_CHANNELMASK, &channelMask),
+ "%s: %s missing %s field",
+ __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_CHANNELMASK);
+ int32_t frameCount = 0;
+ ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount),
+ "%s: %s missing %s field",
+ __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_FRAMECOUNT);
+ int32_t sampleRate = 0;
+ ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate),
+ "%s: %s missing %s field",
+ __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_SAMPLERATE);
+ double speed = 0.f; // default is 1.f
+ ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_PLAYBACK_SPEED, &speed),
+ "%s: %s missing %s field",
+ __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_PLAYBACK_SPEED);
+ double pitch = 0.f; // default is 1.f
+ ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_PLAYBACK_PITCH, &pitch),
+ "%s: %s missing %s field",
+ __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_PLAYBACK_PITCH);
+ const auto [ result, str ] = sendToStatsd(AudioTrackStatusFields,
+ CONDITION(android::util::MEDIAMETRICS_AUDIOTRACKSTATUS_REPORTED)
+ , atom_status
+ , message.c_str()
+ , subCode
+ , uid
+ , event
+ , flags
+ , contentType
+ , usage
+ , encoding
+ , (int64_t)channelMask
+ , frameCount
+ , sampleRate
+ , (float)speed
+ , (float)pitch
+ );
+ ALOGV("%s: statsd %s", __func__, str.c_str());
+ mStatsdLog->log(android::util::MEDIAMETRICS_AUDIOTRACKSTATUS_REPORTED, str);
+ }
+}
+
// HELPER METHODS
std::string AudioAnalytics::getThreadFromTrack(const std::string& track) const
diff --git a/services/mediametrics/AudioPowerUsage.cpp b/services/mediametrics/AudioPowerUsage.cpp
index ab74c8e..5787e9e 100644
--- a/services/mediametrics/AudioPowerUsage.cpp
+++ b/services/mediametrics/AudioPowerUsage.cpp
@@ -45,6 +45,10 @@
#define AUDIO_POWER_USAGE_PROP_DURATION_NS "durationNs" // int64
#define AUDIO_POWER_USAGE_PROP_TYPE "type" // int32
#define AUDIO_POWER_USAGE_PROP_VOLUME "volume" // double
+#define AUDIO_POWER_USAGE_PROP_MIN_VOLUME_DURATION_NS "minVolumeDurationNs" // int64
+#define AUDIO_POWER_USAGE_PROP_MIN_VOLUME "minVolume" // double
+#define AUDIO_POWER_USAGE_PROP_MAX_VOLUME_DURATION_NS "maxVolumeDurationNs" // int64
+#define AUDIO_POWER_USAGE_PROP_MAX_VOLUME "maxVolume" // double
namespace android::mediametrics {
@@ -141,13 +145,34 @@
double volume;
if (!item->getDouble(AUDIO_POWER_USAGE_PROP_VOLUME, &volume)) return;
+ int64_t min_volume_duration_ns;
+ if (!item->getInt64(AUDIO_POWER_USAGE_PROP_MIN_VOLUME_DURATION_NS, &min_volume_duration_ns)) {
+ return;
+ }
+
+ double min_volume;
+ if (!item->getDouble(AUDIO_POWER_USAGE_PROP_MIN_VOLUME, &min_volume)) return;
+
+ int64_t max_volume_duration_ns;
+ if (!item->getInt64(AUDIO_POWER_USAGE_PROP_MAX_VOLUME_DURATION_NS, &max_volume_duration_ns)) {
+ return;
+ }
+
+ double max_volume;
+ if (!item->getDouble(AUDIO_POWER_USAGE_PROP_MAX_VOLUME, &max_volume)) return;
+
const int32_t duration_secs = (int32_t)(duration_ns / NANOS_PER_SECOND);
- const float average_volume = (float)volume;
+ const int32_t min_volume_duration_secs = (int32_t)(min_volume_duration_ns / NANOS_PER_SECOND);
+ const int32_t max_volume_duration_secs = (int32_t)(max_volume_duration_ns / NANOS_PER_SECOND);
const int result = android::util::stats_write(android::util::AUDIO_POWER_USAGE_DATA_REPORTED,
audio_device,
duration_secs,
- average_volume,
- type);
+ (float)volume,
+ type,
+ min_volume_duration_secs,
+ (float)min_volume,
+ max_volume_duration_secs,
+ (float)max_volume);
std::stringstream log;
log << "result:" << result << " {"
@@ -155,17 +180,43 @@
<< android::util::AUDIO_POWER_USAGE_DATA_REPORTED
<< " audio_device:" << audio_device
<< " duration_secs:" << duration_secs
- << " average_volume:" << average_volume
+ << " average_volume:" << (float)volume
<< " type:" << type
+ << " min_volume_duration_secs:" << min_volume_duration_secs
+ << " min_volume:" << (float)min_volume
+ << " max_volume_duration_secs:" << max_volume_duration_secs
+ << " max_volume:" << (float)max_volume
<< " }";
mStatsdLog->log(android::util::AUDIO_POWER_USAGE_DATA_REPORTED, log.str());
}
+void AudioPowerUsage::updateMinMaxVolumeAndDuration(
+ const int64_t cur_max_volume_duration_ns, const double cur_max_volume,
+ const int64_t cur_min_volume_duration_ns, const double cur_min_volume,
+ int64_t& f_max_volume_duration_ns, double& f_max_volume,
+ int64_t& f_min_volume_duration_ns, double& f_min_volume)
+{
+ if (f_min_volume > cur_min_volume) {
+ f_min_volume = cur_min_volume;
+ f_min_volume_duration_ns = cur_min_volume_duration_ns;
+ } else if (f_min_volume == cur_min_volume) {
+ f_min_volume_duration_ns += cur_min_volume_duration_ns;
+ }
+ if (f_max_volume < cur_max_volume) {
+ f_max_volume = cur_max_volume;
+ f_max_volume_duration_ns = cur_max_volume_duration_ns;
+ } else if (f_max_volume == cur_max_volume) {
+ f_max_volume_duration_ns += cur_max_volume_duration_ns;
+ }
+}
+
bool AudioPowerUsage::saveAsItem_l(
- int32_t device, int64_t duration_ns, int32_t type, double average_vol)
+ int32_t device, int64_t duration_ns, int32_t type, double average_vol,
+ int64_t max_volume_duration_ns, double max_volume,
+ int64_t min_volume_duration_ns, double min_volume)
{
ALOGV("%s: (%#x, %d, %lld, %f)", __func__, device, type,
- (long long)duration_ns, average_vol );
+ (long long)duration_ns, average_vol);
if (duration_ns == 0) {
return true; // skip duration 0 usage
}
@@ -193,10 +244,36 @@
item->setDouble(AUDIO_POWER_USAGE_PROP_VOLUME, final_volume);
item->setTimestamp(systemTime(SYSTEM_TIME_REALTIME));
- ALOGV("%s: update (%#x, %d, %lld, %f) --> (%lld, %f)", __func__,
+ // Update the max/min volume and duration
+ int64_t final_min_volume_duration_ns;
+ int64_t final_max_volume_duration_ns;
+ double final_min_volume;
+ double final_max_volume;
+
+ item->getInt64(AUDIO_POWER_USAGE_PROP_MIN_VOLUME_DURATION_NS,
+ &final_min_volume_duration_ns);
+ item->getDouble(AUDIO_POWER_USAGE_PROP_MIN_VOLUME, &final_min_volume);
+ item->getInt64(AUDIO_POWER_USAGE_PROP_MAX_VOLUME_DURATION_NS,
+ &final_max_volume_duration_ns);
+ item->getDouble(AUDIO_POWER_USAGE_PROP_MAX_VOLUME, &final_max_volume);
+ updateMinMaxVolumeAndDuration(max_volume_duration_ns, max_volume,
+ min_volume_duration_ns, min_volume,
+ final_max_volume_duration_ns, final_max_volume,
+ final_min_volume_duration_ns, final_min_volume);
+ item->setInt64(AUDIO_POWER_USAGE_PROP_MIN_VOLUME_DURATION_NS,
+ final_min_volume_duration_ns);
+ item->setDouble(AUDIO_POWER_USAGE_PROP_MIN_VOLUME, final_min_volume);
+ item->setInt64(AUDIO_POWER_USAGE_PROP_MAX_VOLUME_DURATION_NS,
+ final_max_volume_duration_ns);
+ item->setDouble(AUDIO_POWER_USAGE_PROP_MAX_VOLUME, final_max_volume);
+
+ ALOGV("%s: update (%#x, %d, %lld, %f) --> (%lld, %f) min(%lld, %f) max(%lld, %f)",
+ __func__,
device, type,
(long long)item_duration_ns, item_volume,
- (long long)final_duration_ns, final_volume);
+ (long long)final_duration_ns, final_volume,
+ (long long)final_min_volume_duration_ns, final_min_volume,
+ (long long)final_max_volume_duration_ns, final_max_volume);
return true;
}
@@ -208,12 +285,18 @@
sitem->setInt64(AUDIO_POWER_USAGE_PROP_DURATION_NS, duration_ns);
sitem->setInt32(AUDIO_POWER_USAGE_PROP_TYPE, type);
sitem->setDouble(AUDIO_POWER_USAGE_PROP_VOLUME, average_vol);
+ sitem->setInt64(AUDIO_POWER_USAGE_PROP_MIN_VOLUME_DURATION_NS, min_volume_duration_ns);
+ sitem->setDouble(AUDIO_POWER_USAGE_PROP_MIN_VOLUME, min_volume);
+ sitem->setInt64(AUDIO_POWER_USAGE_PROP_MAX_VOLUME_DURATION_NS, max_volume_duration_ns);
+ sitem->setDouble(AUDIO_POWER_USAGE_PROP_MAX_VOLUME, max_volume);
mItems.emplace_back(sitem);
return true;
}
bool AudioPowerUsage::saveAsItems_l(
- int32_t device, int64_t duration_ns, int32_t type, double average_vol)
+ int32_t device, int64_t duration_ns, int32_t type, double average_vol,
+ int64_t max_volume_duration, double max_volume,
+ int64_t min_volume_duration, double min_volume)
{
ALOGV("%s: (%#x, %d, %lld, %f)", __func__, device, type,
(long long)duration_ns, average_vol );
@@ -232,7 +315,9 @@
int32_t tmp_device = device_bits & -device_bits; // get lowest bit
device_bits ^= tmp_device; // clear lowest bit
tmp_device |= input_bit; // restore input bit
- ret = saveAsItem_l(tmp_device, duration_ns, type, average_vol);
+ ret = saveAsItem_l(tmp_device, duration_ns, type, average_vol,
+ max_volume_duration, max_volume,
+ min_volume_duration, min_volume);
ALOGV("%s: device %#x recorded, remaining device_bits = %#x", __func__,
tmp_device, device_bits);
@@ -250,9 +335,28 @@
return;
}
double deviceVolume = 1.;
- if (isTrack && !item->getDouble(AMEDIAMETRICS_PROP_DEVICEVOLUME, &deviceVolume)) {
- return;
+ int64_t maxVolumeDurationNs = 0;
+ double maxVolume = AMEDIAMETRICS_INITIAL_MAX_VOLUME;
+ int64_t minVolumeDurationNs = 0;
+ double minVolume = AMEDIAMETRICS_INITIAL_MIN_VOLUME;
+ if (isTrack) {
+ if (!item->getDouble(AMEDIAMETRICS_PROP_DEVICEVOLUME, &deviceVolume)) {
+ return;
+ }
+ if (!item->getInt64(AMEDIAMETRICS_PROP_DEVICEMAXVOLUMEDURATIONNS, &maxVolumeDurationNs)) {
+ return;
+ }
+ if (!item->getDouble(AMEDIAMETRICS_PROP_DEVICEMAXVOLUME, &maxVolume)) {
+ return;
+ }
+ if (!item->getInt64(AMEDIAMETRICS_PROP_DEVICEMINVOLUMEDURATIONNS, &minVolumeDurationNs)) {
+ return;
+ }
+ if (!item->getDouble(AMEDIAMETRICS_PROP_DEVICEMINVOLUME, &minVolume)) {
+ return;
+ }
}
+
int32_t type = 0;
std::string type_string;
if ((isTrack && mAudioAnalytics->mAnalyticsState->timeMachine().get(
@@ -285,7 +389,8 @@
ALOGV("device = %s => %d", device_strings.c_str(), device);
}
std::lock_guard l(mLock);
- saveAsItems_l(device, deviceTimeNs, type, deviceVolume);
+ saveAsItems_l(device, deviceTimeNs, type, deviceVolume,
+ maxVolumeDurationNs, maxVolume, minVolumeDurationNs, minVolume);
}
void AudioPowerUsage::checkMode(const std::shared_ptr<const mediametrics::Item>& item)
@@ -299,10 +404,17 @@
if (mMode == "AUDIO_MODE_IN_CALL") { // leaving call mode
const int64_t endCallNs = item->getTimestamp();
const int64_t durationNs = endCallNs - mDeviceTimeNs;
+ const int64_t volumeDurationNs = endCallNs - mVolumeTimeNs;
if (durationNs > 0) {
mDeviceVolume = (mDeviceVolume * double(mVolumeTimeNs - mDeviceTimeNs) +
- mVoiceVolume * double(endCallNs - mVolumeTimeNs)) / (double)durationNs;
- saveAsItems_l(mPrimaryDevice, durationNs, VOICE_CALL_TYPE, mDeviceVolume);
+ mVoiceVolume * double(volumeDurationNs)) / (double)durationNs;
+ updateMinMaxVolumeAndDuration(volumeDurationNs, mVoiceVolume,
+ volumeDurationNs, mVoiceVolume,
+ mMaxVoiceVolumeDurationNs, mMaxVoiceVolume,
+ mMinVoiceVolumeDurationNs, mMinVoiceVolume);
+ saveAsItems_l(mPrimaryDevice, durationNs, VOICE_CALL_TYPE, mDeviceVolume,
+ mMaxVoiceVolumeDurationNs, mMaxVoiceVolume,
+ mMinVoiceVolumeDurationNs, mMinVoiceVolume);
}
} else if (mode == "AUDIO_MODE_IN_CALL") { // entering call mode
mStartCallNs = item->getTimestamp(); // advisory only
@@ -327,10 +439,15 @@
if (mMode == "AUDIO_MODE_IN_CALL") {
const int64_t timeNs = item->getTimestamp();
const int64_t durationNs = timeNs - mDeviceTimeNs;
+ const int64_t volumeDurationNs = timeNs - mVolumeTimeNs;
if (durationNs > 0) {
mDeviceVolume = (mDeviceVolume * double(mVolumeTimeNs - mDeviceTimeNs) +
- mVoiceVolume * double(timeNs - mVolumeTimeNs)) / (double)durationNs;
+ mVoiceVolume * double(volumeDurationNs)) / (double)durationNs;
mVolumeTimeNs = timeNs;
+ updateMinMaxVolumeAndDuration(volumeDurationNs, mVoiceVolume,
+ volumeDurationNs, mVoiceVolume,
+ mMaxVoiceVolumeDurationNs, mMaxVoiceVolume,
+ mMinVoiceVolumeDurationNs, mMinVoiceVolume);
}
}
ALOGV("%s: new voice volume:%lf old voice volume:%lf", __func__, voiceVolume, mVoiceVolume);
@@ -358,15 +475,26 @@
// Save statistics
const int64_t endDeviceNs = item->getTimestamp();
const int64_t durationNs = endDeviceNs - mDeviceTimeNs;
+ const int64_t volumeDurationNs = endDeviceNs - mVolumeTimeNs;
if (durationNs > 0) {
mDeviceVolume = (mDeviceVolume * double(mVolumeTimeNs - mDeviceTimeNs) +
- mVoiceVolume * double(endDeviceNs - mVolumeTimeNs)) / (double)durationNs;
- saveAsItems_l(mPrimaryDevice, durationNs, VOICE_CALL_TYPE, mDeviceVolume);
+ mVoiceVolume * double(volumeDurationNs)) / (double)durationNs;
+ updateMinMaxVolumeAndDuration(volumeDurationNs, mVoiceVolume,
+ volumeDurationNs, mVoiceVolume,
+ mMaxVoiceVolumeDurationNs, mMaxVoiceVolume,
+ mMinVoiceVolumeDurationNs, mMinVoiceVolume);
+ saveAsItems_l(mPrimaryDevice, durationNs, VOICE_CALL_TYPE, mDeviceVolume,
+ mMaxVoiceVolumeDurationNs, mMaxVoiceVolume,
+ mMinVoiceVolumeDurationNs, mMinVoiceVolume);
}
// reset statistics
mDeviceVolume = 0;
mDeviceTimeNs = endDeviceNs;
mVolumeTimeNs = endDeviceNs;
+ mMaxVoiceVolume = AMEDIAMETRICS_INITIAL_MAX_VOLUME;
+ mMinVoiceVolume = AMEDIAMETRICS_INITIAL_MIN_VOLUME;
+ mMaxVoiceVolumeDurationNs = 0;
+ mMinVoiceVolumeDurationNs = 0;
}
ALOGV("%s: new primary device:%#x old primary device:%#x", __func__, device, mPrimaryDevice);
mPrimaryDevice = device;
diff --git a/services/mediametrics/AudioTypes.cpp b/services/mediametrics/AudioTypes.cpp
index 838cdd5..7e406cc 100644
--- a/services/mediametrics/AudioTypes.cpp
+++ b/services/mediametrics/AudioTypes.cpp
@@ -15,8 +15,10 @@
*/
#include "AudioTypes.h"
+#include "MediaMetricsConstants.h"
#include "StringUtils.h"
#include <media/TypeConverter.h> // requires libmedia_helper to get the Audio code.
+#include <statslog.h> // statsd
namespace android::mediametrics::types {
@@ -190,6 +192,31 @@
return map;
}
+const std::unordered_map<std::string, int32_t>& getStatusMap() {
+ // DO NOT MODIFY VALUES(OK to add new ones).
+ static std::unordered_map<std::string, int32_t> map {
+ {"",
+ util::MEDIAMETRICS_AUDIO_TRACK_STATUS_REPORTED__STATUS__OK},
+ {AMEDIAMETRICS_PROP_STATUS_VALUE_OK,
+ util::MEDIAMETRICS_AUDIO_TRACK_STATUS_REPORTED__STATUS__OK},
+ {AMEDIAMETRICS_PROP_STATUS_VALUE_ARGUMENT,
+ util::MEDIAMETRICS_AUDIO_TRACK_STATUS_REPORTED__STATUS__ERROR_ARGUMENT},
+ {AMEDIAMETRICS_PROP_STATUS_VALUE_IO,
+ util::MEDIAMETRICS_AUDIO_TRACK_STATUS_REPORTED__STATUS__ERROR_IO},
+ {AMEDIAMETRICS_PROP_STATUS_VALUE_MEMORY,
+ util::MEDIAMETRICS_AUDIO_TRACK_STATUS_REPORTED__STATUS__ERROR_MEMORY},
+ {AMEDIAMETRICS_PROP_STATUS_VALUE_SECURITY,
+ util::MEDIAMETRICS_AUDIO_TRACK_STATUS_REPORTED__STATUS__ERROR_SECURITY},
+ {AMEDIAMETRICS_PROP_STATUS_VALUE_STATE,
+ util::MEDIAMETRICS_AUDIO_TRACK_STATUS_REPORTED__STATUS__ERROR_STATE},
+ {AMEDIAMETRICS_PROP_STATUS_VALUE_TIMEOUT,
+ util::MEDIAMETRICS_AUDIO_TRACK_STATUS_REPORTED__STATUS__ERROR_TIMEOUT},
+ {AMEDIAMETRICS_PROP_STATUS_VALUE_UNKNOWN,
+ util::MEDIAMETRICS_AUDIO_TRACK_STATUS_REPORTED__STATUS__ERROR_UNKNOWN},
+ };
+ return map;
+}
+
// Helper: Create the corresponding int32 from string flags split with '|'.
template <typename Traits>
int32_t int32FromFlags(const std::string &flags)
@@ -431,6 +458,17 @@
}
template <>
+int32_t lookup<STATUS>(const std::string &status)
+{
+ auto& map = getStatusMap();
+ auto it = map.find(status);
+ if (it == map.end()) {
+ return util::MEDIAMETRICS_AUDIO_TRACK_STATUS_REPORTED__STATUS__ERROR_UNKNOWN;
+ }
+ return it->second;
+}
+
+template <>
int32_t lookup<THREAD_TYPE>(const std::string &threadType)
{
auto& map = getAudioThreadTypeMap();
diff --git a/services/mediametrics/MediaMetricsService.cpp b/services/mediametrics/MediaMetricsService.cpp
index 35e0ae4..636b343 100644
--- a/services/mediametrics/MediaMetricsService.cpp
+++ b/services/mediametrics/MediaMetricsService.cpp
@@ -319,11 +319,19 @@
result << "-- some lines may be truncated --\n";
}
- result << "LogSessionId:\n"
+ const int32_t heatLinesToDump = all ? INT32_MAX : 20;
+ const auto [ heatDumpString, heatLines] =
+ mAudioAnalytics.dumpHeatMap(heatLinesToDump);
+ result << "\n" << heatDumpString;
+ if (heatLines == heatLinesToDump) {
+ result << "-- some lines may be truncated --\n";
+ }
+
+ result << "\nLogSessionId:\n"
<< mediametrics::ValidateId::get()->dump();
// Dump the statsd atoms we sent out.
- result << "Statsd atoms:\n"
+ result << "\nStatsd atoms:\n"
<< mStatsdLog->dumpToString(" " /* prefix */,
all ? STATSD_LOG_LINES_MAX : STATSD_LOG_LINES_DUMP);
}
diff --git a/services/mediametrics/fuzzer/Android.bp b/services/mediametrics/fuzzer/Android.bp
index 9da7282..84d494e 100644
--- a/services/mediametrics/fuzzer/Android.bp
+++ b/services/mediametrics/fuzzer/Android.bp
@@ -59,9 +59,8 @@
"packagemanager_aidl-cpp",
],
- include_dirs: [
- "frameworks/av/services/mediametrics",
- "system/media/audio_utils/include",
+ header_libs: [
+ "libaudioutils_headers",
],
fuzz_config: {
diff --git a/services/mediametrics/fuzzer/mediametrics_service_fuzzer.cpp b/services/mediametrics/fuzzer/mediametrics_service_fuzzer.cpp
index 06ab16e..433332c 100644
--- a/services/mediametrics/fuzzer/mediametrics_service_fuzzer.cpp
+++ b/services/mediametrics/fuzzer/mediametrics_service_fuzzer.cpp
@@ -19,15 +19,14 @@
*/
#include <fuzzer/FuzzedDataProvider.h>
#include <media/MediaMetricsItem.h>
+#include <mediametricsservice/AudioTypes.h>
+#include <mediametricsservice/MediaMetricsService.h>
+#include <mediametricsservice/StringUtils.h>
#include <stdio.h>
#include <string.h>
#include <utils/Log.h>
#include <algorithm>
-#include "AudioTypes.h"
-#include "MediaMetricsService.h"
-#include "StringUtils.h"
-
using namespace android;
// low water mark
diff --git a/services/mediametrics/AnalyticsActions.h b/services/mediametrics/include/mediametricsservice/AnalyticsActions.h
similarity index 100%
rename from services/mediametrics/AnalyticsActions.h
rename to services/mediametrics/include/mediametricsservice/AnalyticsActions.h
diff --git a/services/mediametrics/AnalyticsState.h b/services/mediametrics/include/mediametricsservice/AnalyticsState.h
similarity index 100%
rename from services/mediametrics/AnalyticsState.h
rename to services/mediametrics/include/mediametricsservice/AnalyticsState.h
diff --git a/services/mediametrics/AudioAnalytics.h b/services/mediametrics/include/mediametricsservice/AudioAnalytics.h
similarity index 90%
rename from services/mediametrics/AudioAnalytics.h
rename to services/mediametrics/include/mediametricsservice/AudioAnalytics.h
index 2b41a95..9b54cf3 100644
--- a/services/mediametrics/AudioAnalytics.h
+++ b/services/mediametrics/include/mediametricsservice/AudioAnalytics.h
@@ -20,6 +20,7 @@
#include "AnalyticsActions.h"
#include "AnalyticsState.h"
#include "AudioPowerUsage.h"
+#include "HeatMap.h"
#include "StatsdLog.h"
#include "TimedAction.h"
#include "Wrap.h"
@@ -73,11 +74,23 @@
std::pair<std::string, int32_t> dump(
int32_t lines = INT32_MAX, int64_t sinceNs = 0, const char *prefix = nullptr) const;
+ /**
+ * Returns a pair consisting of the dump string and the number of lines in the string.
+ *
+ * HeatMap dump.
+ */
+ std::pair<std::string, int32_t> dumpHeatMap(int32_t lines = INT32_MAX) const {
+ return mHeatMap.dump(lines);
+ }
+
void clear() {
// underlying state is locked.
mPreviousAnalyticsState->clear();
mAnalyticsState->clear();
+ // Clears the status map
+ mHeatMap.clear();
+
// Clear power usage state.
mAudioPowerUsage.clear();
}
@@ -96,11 +109,18 @@
*/
/**
- * Checks for any pending actions for a particular item.
+ * Processes any pending actions for a particular item.
*
* \param item to check against the current AnalyticsActions.
*/
- void checkActions(const std::shared_ptr<const mediametrics::Item>& item);
+ void processActions(const std::shared_ptr<const mediametrics::Item>& item);
+
+ /**
+ * Processes status information contained in the item.
+ *
+ * \param item to check against for status handling
+ */
+ void processStatus(const std::shared_ptr<const mediametrics::Item>& item);
// HELPER METHODS
/**
@@ -124,6 +144,9 @@
TimedAction mTimedAction; // locked internally
const std::shared_ptr<StatsdLog> mStatsdLog; // locked internally, ok for multiple threads.
+ static constexpr size_t kHeatEntries = 100;
+ HeatMap mHeatMap{kHeatEntries}; // locked internally, ok for multiple threads.
+
// DeviceUse is a nested class which handles audio device usage accounting.
// We define this class at the end to ensure prior variables all properly constructed.
// TODO: Track / Thread interaction
diff --git a/services/mediametrics/AudioPowerUsage.h b/services/mediametrics/include/mediametricsservice/AudioPowerUsage.h
similarity index 80%
rename from services/mediametrics/AudioPowerUsage.h
rename to services/mediametrics/include/mediametricsservice/AudioPowerUsage.h
index 7021902..b7215e6 100644
--- a/services/mediametrics/AudioPowerUsage.h
+++ b/services/mediametrics/include/mediametricsservice/AudioPowerUsage.h
@@ -26,6 +26,7 @@
namespace android::mediametrics {
+
class AudioAnalytics;
class AudioPowerUsage {
@@ -83,13 +84,21 @@
static bool deviceFromString(const std::string& device_string, int32_t& device);
static int32_t deviceFromStringPairs(const std::string& device_strings);
private:
- bool saveAsItem_l(int32_t device, int64_t duration, int32_t type, double average_vol)
- REQUIRES(mLock);
+ bool saveAsItem_l(int32_t device, int64_t duration, int32_t type, double average_vol,
+ int64_t max_volume_duration, double max_volume,
+ int64_t min_volume_duration, double min_volume)
+ REQUIRES(mLock);
void sendItem(const std::shared_ptr<const mediametrics::Item>& item) const;
void collect();
- bool saveAsItems_l(int32_t device, int64_t duration, int32_t type, double average_vol)
- REQUIRES(mLock);
-
+ bool saveAsItems_l(int32_t device, int64_t duration, int32_t type, double average_vol,
+ int64_t max_volume_duration, double max_volume,
+ int64_t min_volume_duration, double min_volume)
+ REQUIRES(mLock);
+ void updateMinMaxVolumeAndDuration(
+ const int64_t cur_max_volume_duration_ns, const double cur_max_volume,
+ const int64_t cur_min_volume_duration_ns, const double cur_min_volume,
+ int64_t& f_max_volume_duration_ns, double& f_max_volume,
+ int64_t& f_min_volume_duration_ns, double& f_min_volume);
AudioAnalytics * const mAudioAnalytics;
const std::shared_ptr<StatsdLog> mStatsdLog; // mStatsdLog is internally locked
const bool mDisabled;
@@ -100,6 +109,10 @@
double mVoiceVolume GUARDED_BY(mLock) = 0.;
double mDeviceVolume GUARDED_BY(mLock) = 0.;
+ double mMaxVoiceVolume GUARDED_BY(mLock) = AMEDIAMETRICS_INITIAL_MAX_VOLUME;
+ double mMinVoiceVolume GUARDED_BY(mLock) = AMEDIAMETRICS_INITIAL_MIN_VOLUME;
+ int64_t mMaxVoiceVolumeDurationNs GUARDED_BY(mLock) = 0;
+ int64_t mMinVoiceVolumeDurationNs GUARDED_BY(mLock) = 0;
int64_t mStartCallNs GUARDED_BY(mLock) = 0; // advisory only
int64_t mVolumeTimeNs GUARDED_BY(mLock) = 0;
int64_t mDeviceTimeNs GUARDED_BY(mLock) = 0;
diff --git a/services/mediametrics/AudioTypes.h b/services/mediametrics/include/mediametricsservice/AudioTypes.h
similarity index 92%
rename from services/mediametrics/AudioTypes.h
rename to services/mediametrics/include/mediametricsservice/AudioTypes.h
index 4394d79..5dbff9b 100644
--- a/services/mediametrics/AudioTypes.h
+++ b/services/mediametrics/include/mediametricsservice/AudioTypes.h
@@ -39,6 +39,10 @@
};
// Enumeration for all the string translations to integers (generally int32_t) unless noted.
+// This is used to index the template method below:
+// template <AudioEnumCategory C, typename T, typename S> T lookup(const S &str);
+//
+// Okay to keep AudioEnumCategory alphabetical and add new translations in the middle.
enum AudioEnumCategory {
AAUDIO_DIRECTION,
AAUDIO_PERFORMANCE_MODE,
@@ -51,6 +55,7 @@
OUTPUT_DEVICE, // int64_t
OUTPUT_FLAG,
SOURCE_TYPE,
+ STATUS,
STREAM_TYPE,
THREAD_TYPE,
TRACK_TRAITS,
diff --git a/services/mediametrics/include/mediametricsservice/HeatMap.h b/services/mediametrics/include/mediametricsservice/HeatMap.h
new file mode 100644
index 0000000..950501a
--- /dev/null
+++ b/services/mediametrics/include/mediametricsservice/HeatMap.h
@@ -0,0 +1,222 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <iomanip>
+#include <map>
+#include <sstream>
+#include "MediaMetricsConstants.h"
+
+namespace android::mediametrics {
+
+/**
+ * HeatData accumulates statistics on the status reported for a given key.
+ *
+ * HeatData is a helper class used by HeatMap to represent statistics. We expose it
+ * here for testing purposes currently.
+ *
+ * Note: This class is not thread safe, so mutual exclusion should be obtained by the caller
+ * which in this case is HeatMap. HeatMap getData() returns a local copy of HeatData, so use
+ * of that is thread-safe.
+ */
+class HeatData {
+ /* HeatData for a key is stored in a map based on the event (e.g. "start", "pause", create)
+ * and then another map based on the status (e.g. "ok", "argument", "state").
+ */
+ std::map<std::string /* event */,
+ std::map<std::string /* status name */, size_t /* count, nonzero */>> mMap;
+
+public:
+ /**
+ * Add status data.
+ *
+ * \param suffix (ignored) the suffix to the key that was stripped, if any.
+ * \param event the event (e.g. create, start, pause, stop, etc.).
+ * \param uid (ignored) the uid associated with the error.
+ * \param message (ignored) the status message, if any.
+ * \param subCode (ignored) the status subcode, if any.
+ */
+ void add(const std::string& suffix, const std::string& event, const std::string& status,
+ uid_t uid, const std::string& message, int32_t subCode) {
+ // Perhaps there could be a more detailed print.
+ (void)suffix;
+ (void)uid;
+ (void)message;
+ (void)subCode;
+ ++mMap[event][status];
+ }
+
+ /** Returns the number of event names with status. */
+ size_t size() const {
+ return mMap.size();
+ }
+
+ /**
+ * Returns a deque with pairs indicating the count of Oks and Errors.
+ * The first pair is total, the other pairs are in order of mMap.
+ *
+ * Example return value of {ok, error} pairs:
+ * total key1 key2
+ * { { 2, 1 }, { 1, 0 }, { 1, 1 } }
+ */
+ std::deque<std::pair<size_t /* oks */, size_t /* errors */>> heatCount() const {
+ size_t totalOk = 0;
+ size_t totalError = 0;
+ std::deque<std::pair<size_t /* oks */, size_t /* errors */>> heat;
+ for (const auto &eventPair : mMap) {
+ size_t ok = 0;
+ size_t error = 0;
+ for (const auto &[name, count] : eventPair.second) {
+ if (name == AMEDIAMETRICS_PROP_STATUS_VALUE_OK) {
+ ok += count;
+ } else {
+ error += count;
+ }
+ }
+ totalOk += ok;
+ totalError += error;
+ heat.emplace_back(ok, error);
+ }
+ heat.emplace_front(totalOk, totalError);
+ return heat;
+ }
+
+ /** Returns the error fraction from a pair <oks, errors>, a float between 0.f to 1.f. */
+ static float fraction(const std::pair<size_t, size_t>& count) {
+ return (float)count.second / (count.first + count.second);
+ }
+
+ /** Returns the HeatMap information in a single line string. */
+ std::string dump() const {
+ const auto heat = heatCount();
+ auto it = heat.begin();
+ std::stringstream ss;
+ ss << "{ ";
+ float errorFraction = fraction(*it++);
+ if (errorFraction > 0.f) {
+ ss << std::fixed << std::setprecision(2) << errorFraction << " ";
+ }
+ for (const auto &eventPair : mMap) {
+ ss << eventPair.first << ": { ";
+ errorFraction = fraction(*it++);
+ if (errorFraction > 0.f) {
+ ss << std::fixed << std::setprecision(2) << errorFraction << " ";
+ }
+ for (const auto &[name, count]: eventPair.second) {
+ ss << "[ " << name << " : " << count << " ] ";
+ }
+ ss << "} ";
+ }
+ ss << " }";
+ return ss.str();
+ }
+};
+
+/**
+ * HeatMap is a thread-safe collection that counts activity of status errors per key.
+ *
+ * The classic heat map is a 2D picture with intensity shown by color.
+ * Here we accumulate the status results from keys to see if there are consistent
+ * failures in the system.
+ *
+ * TODO(b/210855555): Heatmap improvements.
+ * 1) heat decays in intensity in time for past events, currently we don't decay.
+ */
+
+class HeatMap {
+ const size_t mMaxSize;
+ mutable std::mutex mLock;
+ size_t mRejected GUARDED_BY(mLock) = 0;
+ std::map<std::string, HeatData> mMap GUARDED_BY(mLock);
+
+public:
+ /**
+ * Constructs a HeatMap.
+ *
+ * \param maxSize the maximum number of elements that are tracked.
+ */
+ explicit HeatMap(size_t maxSize) : mMaxSize(maxSize) {
+ }
+
+ /** Returns the number of keys. */
+ size_t size() const {
+ std::lock_guard l(mLock);
+ return mMap.size();
+ }
+
+ /** Clears error history. */
+ void clear() {
+ std::lock_guard l(mLock);
+ return mMap.clear();
+ }
+
+ /** Returns number of keys rejected due to space. */
+ size_t rejected() const {
+ std::lock_guard l(mLock);
+ return mRejected;
+ }
+
+ /** Returns a copy of the heat data associated with key. */
+ HeatData getData(const std::string& key) const {
+ std::lock_guard l(mLock);
+ return mMap.count(key) == 0 ? HeatData{} : mMap.at(key);
+ }
+
+ /**
+ * Adds a new entry.
+ * \param key the key category (e.g. audio.track).
+ * \param suffix (ignored) the suffix to the key that was stripped, if any.
+ * \param event the event (e.g. create, start, pause, stop, etc.).
+ * \param uid (ignored) the uid associated with the error.
+ * \param message (ignored) the status message, if any.
+ * \param subCode (ignored) the status subcode, if any.
+ */
+ void add(const std::string& key, const std::string& suffix, const std::string& event,
+ const std::string& status, uid_t uid, const std::string& message, int32_t subCode) {
+ std::lock_guard l(mLock);
+
+ // Hard limit on heat map entries.
+ // TODO: have better GC.
+ if (mMap.size() == mMaxSize && mMap.count(key) == 0) {
+ ++mRejected;
+ return;
+ }
+ mMap[key].add(suffix, event, status, uid, message, subCode);
+ }
+
+ /**
+ * Returns a pair consisting of the dump string and the number of lines in the string.
+ */
+ std::pair<std::string, int32_t> dump(int32_t lines = INT32_MAX) const {
+ std::stringstream ss;
+ int32_t ll = lines;
+ std::lock_guard l(mLock);
+ if (ll > 0) {
+ ss << "Error Heat Map (rejected: " << mRejected << "):\n";
+ --ll;
+ }
+ // TODO: restriction is implemented alphabetically not on priority.
+ for (const auto& [name, data] : mMap) {
+ if (ll <= 0) break;
+ ss << name << ": " << data.dump() << "\n";
+ --ll;
+ }
+ return { ss.str(), lines - ll };
+ }
+};
+
+} // namespace android::mediametrics
diff --git a/services/mediametrics/LruSet.h b/services/mediametrics/include/mediametricsservice/LruSet.h
similarity index 100%
rename from services/mediametrics/LruSet.h
rename to services/mediametrics/include/mediametricsservice/LruSet.h
diff --git a/services/mediametrics/MediaMetricsService.h b/services/mediametrics/include/mediametricsservice/MediaMetricsService.h
similarity index 100%
rename from services/mediametrics/MediaMetricsService.h
rename to services/mediametrics/include/mediametricsservice/MediaMetricsService.h
diff --git a/services/mediametrics/StatsdLog.h b/services/mediametrics/include/mediametricsservice/StatsdLog.h
similarity index 100%
rename from services/mediametrics/StatsdLog.h
rename to services/mediametrics/include/mediametricsservice/StatsdLog.h
diff --git a/services/mediametrics/StringUtils.h b/services/mediametrics/include/mediametricsservice/StringUtils.h
similarity index 83%
rename from services/mediametrics/StringUtils.h
rename to services/mediametrics/include/mediametricsservice/StringUtils.h
index 01034d9..a56f5b8 100644
--- a/services/mediametrics/StringUtils.h
+++ b/services/mediametrics/include/mediametricsservice/StringUtils.h
@@ -167,4 +167,41 @@
return ss.str();
}
+/**
+ * Returns true if the string is non-null, not empty, and contains only digits.
+ */
+inline constexpr bool isNumeric(const char *s)
+{
+ if (s == nullptr || *s == 0) return false;
+ do {
+ if (!isdigit(*s)) return false;
+ } while (*++s != 0);
+ return true; // all digits
+}
+
+/**
+ * Extracts out the prefix from the key, returning a pair of prefix, suffix.
+ *
+ * Usually the key is something like:
+ * Prefix.(ID)
+ * where ID is an integer,
+ * or "error" if the id was not returned because of failure,
+ * or "status" if general status.
+ *
+ * Example: audio.track.10 -> prefix = audio.track, suffix = 10
+ * audio.track.error -> prefix = audio.track, suffix = error
+ * audio.track.status -> prefix = audio.track, suffix = status
+ * audio.mute -> prefix = audio.mute, suffix = ""
+ */
+inline std::pair<std::string /* prefix */,
+ std::string /* suffix */> splitPrefixKey(const std::string &key)
+{
+ const size_t split = key.rfind('.');
+ const char* suffix = key.c_str() + split + 1;
+ if (*suffix && (!strcmp(suffix, "error") || !strcmp(suffix, "status") || isNumeric(suffix))) {
+ return { key.substr(0, split), suffix };
+ }
+ return { key, "" };
+}
+
} // namespace android::mediametrics::stringutils
diff --git a/services/mediametrics/TimeMachine.h b/services/mediametrics/include/mediametricsservice/TimeMachine.h
similarity index 100%
rename from services/mediametrics/TimeMachine.h
rename to services/mediametrics/include/mediametricsservice/TimeMachine.h
diff --git a/services/mediametrics/TimedAction.h b/services/mediametrics/include/mediametricsservice/TimedAction.h
similarity index 100%
rename from services/mediametrics/TimedAction.h
rename to services/mediametrics/include/mediametricsservice/TimedAction.h
diff --git a/services/mediametrics/TransactionLog.h b/services/mediametrics/include/mediametricsservice/TransactionLog.h
similarity index 100%
rename from services/mediametrics/TransactionLog.h
rename to services/mediametrics/include/mediametricsservice/TransactionLog.h
diff --git a/services/mediametrics/ValidateId.h b/services/mediametrics/include/mediametricsservice/ValidateId.h
similarity index 100%
rename from services/mediametrics/ValidateId.h
rename to services/mediametrics/include/mediametricsservice/ValidateId.h
diff --git a/services/mediametrics/Wrap.h b/services/mediametrics/include/mediametricsservice/Wrap.h
similarity index 100%
rename from services/mediametrics/Wrap.h
rename to services/mediametrics/include/mediametricsservice/Wrap.h
diff --git a/services/mediametrics/cleaner.h b/services/mediametrics/include/mediametricsservice/cleaner.h
similarity index 100%
rename from services/mediametrics/cleaner.h
rename to services/mediametrics/include/mediametricsservice/cleaner.h
diff --git a/services/mediametrics/iface_statsd.h b/services/mediametrics/include/mediametricsservice/iface_statsd.h
similarity index 100%
rename from services/mediametrics/iface_statsd.h
rename to services/mediametrics/include/mediametricsservice/iface_statsd.h
diff --git a/services/mediametrics/main_mediametrics.cpp b/services/mediametrics/main_mediametrics.cpp
index 3a66538..455d67a 100644
--- a/services/mediametrics/main_mediametrics.cpp
+++ b/services/mediametrics/main_mediametrics.cpp
@@ -18,11 +18,10 @@
//#define LOG_NDEBUG 0
#include <utils/Log.h>
-#include "MediaMetricsService.h"
-
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
+#include <mediametricsservice/MediaMetricsService.h>
#include <mediautils/LimitProcessMemory.h>
int main(int argc __unused, char **argv)
diff --git a/services/mediametrics/statsd_audiorecord.cpp b/services/mediametrics/statsd_audiorecord.cpp
index c53b6f3..a7b045e 100644
--- a/services/mediametrics/statsd_audiorecord.cpp
+++ b/services/mediametrics/statsd_audiorecord.cpp
@@ -80,16 +80,20 @@
}
int64_t created_millis = -1;
+ // not currently sent from client.
if (item->getInt64("android.media.audiorecord.createdMs", &created_millis)) {
metrics_proto.set_created_millis(created_millis);
}
int64_t duration_millis = -1;
- if (item->getInt64("android.media.audiorecord.durationMs", &duration_millis)) {
+ double durationMs = 0.;
+ if (item->getDouble("android.media.audiorecord.durationMs", &durationMs)) {
+ duration_millis = (int64_t)durationMs;
metrics_proto.set_duration_millis(duration_millis);
}
int32_t count = -1;
+ // not currently sent from client. (see start count instead).
if (item->getInt32("android.media.audiorecord.n", &count)) {
metrics_proto.set_count(count);
}
@@ -129,7 +133,7 @@
}
int64_t start_count = -1;
- if (item->getInt64("android.media.audiorecord.startcount", &start_count)) {
+ if (item->getInt64("android.media.audiorecord.startCount", &start_count)) {
metrics_proto.set_start_count(start_count);
}
diff --git a/services/mediametrics/statsd_audiotrack.cpp b/services/mediametrics/statsd_audiotrack.cpp
index 707effd..67514e9 100644
--- a/services/mediametrics/statsd_audiotrack.cpp
+++ b/services/mediametrics/statsd_audiotrack.cpp
@@ -56,52 +56,47 @@
// flesh out the protobuf we'll hand off with our data
//
- // static constexpr char kAudioTrackStreamType[] = "android.media.audiotrack.streamtype";
+ // Do not change this without changing AudioTrack.cpp collection.
+
// optional string streamType;
std::string stream_type;
if (item->getString("android.media.audiotrack.streamtype", &stream_type)) {
metrics_proto.set_stream_type(stream_type);
}
- // static constexpr char kAudioTrackContentType[] = "android.media.audiotrack.type";
// optional string contentType;
std::string content_type;
if (item->getString("android.media.audiotrack.type", &content_type)) {
metrics_proto.set_content_type(content_type);
}
- // static constexpr char kAudioTrackUsage[] = "android.media.audiotrack.usage";
// optional string trackUsage;
std::string track_usage;
if (item->getString("android.media.audiotrack.usage", &track_usage)) {
metrics_proto.set_track_usage(track_usage);
}
- // static constexpr char kAudioTrackSampleRate[] = "android.media.audiotrack.samplerate";
- // optional int32 samplerate;
+ // optional int32 sampleRate;
int32_t sample_rate = -1;
- if (item->getInt32("android.media.audiotrack.samplerate", &sample_rate)) {
+ if (item->getInt32("android.media.audiotrack.sampleRate", &sample_rate)) {
metrics_proto.set_sample_rate(sample_rate);
}
- // static constexpr char kAudioTrackChannelMask[] = "android.media.audiotrack.channelmask";
// optional int64 channelMask;
int64_t channel_mask = -1;
- if (item->getInt64("android.media.audiotrack.channelmask", &channel_mask)) {
+ if (item->getInt64("android.media.audiotrack.channelMask", &channel_mask)) {
metrics_proto.set_channel_mask(channel_mask);
}
- // NB: These are not yet exposed as public Java API constants.
- // static constexpr char kAudioTrackUnderrunFrames[] = "android.media.audiotrack.underrunframes";
- // optional int32 underrunframes;
+ // optional int32 underrunFrames;
int32_t underrun_frames = -1;
- if (item->getInt32("android.media.audiotrack.underrunframes", &underrun_frames)) {
+ if (item->getInt32("android.media.audiotrack.underrunFrames", &underrun_frames)) {
metrics_proto.set_underrun_frames(underrun_frames);
}
- // static constexpr char kAudioTrackStartupGlitch[] = "android.media.audiotrack.glitch.startup";
- // optional int32 startupglitch;
+ // optional int32 glitch.startup;
int32_t startup_glitch = -1;
+ // Not currently sent from client.
if (item->getInt32("android.media.audiotrack.glitch.startup", &startup_glitch)) {
metrics_proto.set_startup_glitch(startup_glitch);
}
diff --git a/services/mediametrics/tests/mediametrics_tests.cpp b/services/mediametrics/tests/mediametrics_tests.cpp
index cd6af9f..bc7b47b 100644
--- a/services/mediametrics/tests/mediametrics_tests.cpp
+++ b/services/mediametrics/tests/mediametrics_tests.cpp
@@ -17,19 +17,18 @@
#define LOG_TAG "mediametrics_tests"
#include <utils/Log.h>
-#include "MediaMetricsService.h"
#include <stdio.h>
#include <unordered_set>
#include <gtest/gtest.h>
#include <media/MediaMetricsItem.h>
+#include <mediametricsservice/AudioTypes.h>
+#include <mediametricsservice/MediaMetricsService.h>
+#include <mediametricsservice/StringUtils.h>
+#include <mediametricsservice/ValidateId.h>
#include <system/audio.h>
-#include "AudioTypes.h"
-#include "StringUtils.h"
-#include "ValidateId.h"
-
using namespace android;
static size_t countNewlines(const char *s) {
@@ -1226,8 +1225,8 @@
}
}
-TEST(mediametrics_tests, ErrorConversion) {
- constexpr status_t errors[] = {
+TEST(mediametrics_tests, StatusConversion) {
+ constexpr status_t statuses[] = {
NO_ERROR,
BAD_VALUE,
DEAD_OBJECT,
@@ -1239,15 +1238,58 @@
};
auto roundTrip = [](status_t status) {
- return android::mediametrics::errorStringToStatus(
- android::mediametrics::statusToErrorString(status));
+ return android::mediametrics::statusStringToStatus(
+ android::mediametrics::statusToStatusString(status));
};
// Primary status error categories.
- for (const auto error : errors) {
- ASSERT_EQ(error, roundTrip(error));
+ for (const auto status : statuses) {
+ ASSERT_EQ(status, roundTrip(status));
}
// Status errors specially considered.
ASSERT_EQ(DEAD_OBJECT, roundTrip(FAILED_TRANSACTION));
}
+
+TEST(mediametrics_tests, HeatMap) {
+ constexpr size_t SIZE = 2;
+ android::mediametrics::HeatMap heatMap{SIZE};
+ constexpr uid_t UID = 0;
+ constexpr int32_t SUBCODE = 1;
+
+ ASSERT_EQ((size_t)0, heatMap.size());
+ heatMap.add("someKey", "someSuffix", "someEvent",
+ AMEDIAMETRICS_PROP_STATUS_VALUE_OK, UID, "message", SUBCODE);
+ ASSERT_EQ((size_t)1, heatMap.size());
+ heatMap.add("someKey", "someSuffix", "someEvent",
+ AMEDIAMETRICS_PROP_STATUS_VALUE_OK, UID, "message", SUBCODE);
+ heatMap.add("someKey", "someSuffix", "anotherEvent",
+ AMEDIAMETRICS_PROP_STATUS_VALUE_ARGUMENT, UID, "message", SUBCODE);
+ ASSERT_EQ((size_t)1, heatMap.size());
+ heatMap.add("anotherKey", "someSuffix", "someEvent",
+ AMEDIAMETRICS_PROP_STATUS_VALUE_OK, UID, "message", SUBCODE);
+ ASSERT_EQ((size_t)2, heatMap.size());
+ ASSERT_EQ((size_t)0, heatMap.rejected());
+
+ heatMap.add("thirdKey", "someSuffix", "someEvent",
+ AMEDIAMETRICS_PROP_STATUS_VALUE_OK, UID, "message", SUBCODE);
+ ASSERT_EQ((size_t)2, heatMap.size());
+ ASSERT_EQ((size_t)1, heatMap.rejected());
+
+ android::mediametrics::HeatData heatData = heatMap.getData("someKey");
+ ASSERT_EQ((size_t)2, heatData.size());
+ auto count = heatData.heatCount();
+ ASSERT_EQ((size_t)3, count.size()); // pairs in order { total, "anotherEvent", "someEvent" }
+ // check total value
+ ASSERT_EQ((size_t)2, count[0].first); // OK
+ ASSERT_EQ((size_t)1, count[0].second); // ERROR;
+ // first key "anotherEvent"
+ ASSERT_EQ((size_t)0, count[1].first); // OK
+ ASSERT_EQ((size_t)1, count[1].second); // ERROR;
+ // second key "someEvent"
+ ASSERT_EQ((size_t)2, count[2].first); // OK
+ ASSERT_EQ((size_t)0, count[2].second); // ERROR;
+
+ heatMap.clear();
+ ASSERT_EQ((size_t)0, heatMap.size());
+}
diff --git a/services/oboeservice/AAudioCommandQueue.cpp b/services/oboeservice/AAudioCommandQueue.cpp
index ddaabe8..9bd18b3 100644
--- a/services/oboeservice/AAudioCommandQueue.cpp
+++ b/services/oboeservice/AAudioCommandQueue.cpp
@@ -28,6 +28,10 @@
aaudio_result_t AAudioCommandQueue::sendCommand(std::shared_ptr<AAudioCommand> command) {
{
std::scoped_lock<std::mutex> _l(mLock);
+ if (!mRunning) {
+ ALOGE("Tried to send command while it was not running");
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
mCommands.push(command);
mWaitWorkCond.notify_one();
}
@@ -68,7 +72,7 @@
return !mRunning || !mCommands.empty();
});
}
- if (!mCommands.empty()) {
+ if (!mCommands.empty() && mRunning) {
command = mCommands.front();
mCommands.pop();
}
@@ -76,9 +80,27 @@
return command;
}
+void AAudioCommandQueue::startWaiting() {
+ std::scoped_lock<std::mutex> _l(mLock);
+ mRunning = true;
+}
+
void AAudioCommandQueue::stopWaiting() {
std::scoped_lock<std::mutex> _l(mLock);
mRunning = false;
+ // Clear all commands in the queue as the command thread is stopped.
+ while (!mCommands.empty()) {
+ auto command = mCommands.front();
+ mCommands.pop();
+ std::scoped_lock<std::mutex> _cl(command->lock);
+ // If the command is waiting for result, returns AAUDIO_ERROR_INVALID_STATE
+ // as there is no thread waiting for the command.
+ if (command->isWaitingForReply) {
+ command->result = AAUDIO_ERROR_INVALID_STATE;
+ command->isWaitingForReply = false;
+ command->conditionVariable.notify_one();
+ }
+ }
mWaitWorkCond.notify_one();
}
diff --git a/services/oboeservice/AAudioCommandQueue.h b/services/oboeservice/AAudioCommandQueue.h
index 5f25507..64442a3 100644
--- a/services/oboeservice/AAudioCommandQueue.h
+++ b/services/oboeservice/AAudioCommandQueue.h
@@ -78,6 +78,12 @@
std::shared_ptr<AAudioCommand> waitForCommand(int64_t timeoutNanos = -1);
/**
+ * Start waiting for commands. Commands can only be pushed into the command queue after it
+ * starts waiting.
+ */
+ void startWaiting();
+
+ /**
* Force stop waiting for next command
*/
void stopWaiting();
@@ -87,7 +93,7 @@
std::condition_variable mWaitWorkCond;
std::queue<std::shared_ptr<AAudioCommand>> mCommands GUARDED_BY(mLock);
- bool mRunning GUARDED_BY(mLock) = true;
+ bool mRunning GUARDED_BY(mLock) = false;
};
} // namespace aaudio
\ No newline at end of file
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index 40a664e..2679b2e 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -280,6 +280,22 @@
AIDL_RETURN(serviceStream->unregisterAudioThread(clientThreadId));
}
+Status AAudioService::exitStandby(int32_t streamHandle, Endpoint* endpoint, int32_t *_aidl_return) {
+ static_assert(std::is_same_v<aaudio_result_t, std::decay_t<typeof(*_aidl_return)>>);
+
+ sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+ if (serviceStream.get() == nullptr) {
+ ALOGE("getStreamDescription(), illegal stream handle = 0x%0x", streamHandle);
+ AIDL_RETURN(AAUDIO_ERROR_INVALID_HANDLE);
+ }
+ AudioEndpointParcelable endpointParcelable;
+ aaudio_result_t result = serviceStream->exitStandby(&endpointParcelable);
+ if (result == AAUDIO_OK) {
+ *endpoint = std::move(endpointParcelable).parcelable();
+ }
+ AIDL_RETURN(result);
+}
+
bool AAudioService::isCallerInService() {
pid_t clientPid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(mAudioClient.attributionSource.pid));
uid_t clientUid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(mAudioClient.attributionSource.uid));
diff --git a/services/oboeservice/AAudioService.h b/services/oboeservice/AAudioService.h
index 7c1b796..0a111fb 100644
--- a/services/oboeservice/AAudioService.h
+++ b/services/oboeservice/AAudioService.h
@@ -82,6 +82,9 @@
binder::Status unregisterAudioThread(int32_t streamHandle, int32_t clientThreadId,
int32_t* _aidl_return) override;
+ binder::Status exitStandby(int32_t streamHandle, ::aaudio::Endpoint* endpoint,
+ int32_t* _aidl_return) override;
+
aaudio_result_t startClient(aaudio::aaudio_handle_t streamHandle,
const android::AudioClient& client,
const audio_attributes_t *attr,
diff --git a/services/oboeservice/AAudioServiceEndpoint.h b/services/oboeservice/AAudioServiceEndpoint.h
index a7f63d3..92004c5 100644
--- a/services/oboeservice/AAudioServiceEndpoint.h
+++ b/services/oboeservice/AAudioServiceEndpoint.h
@@ -77,6 +77,16 @@
return AAUDIO_ERROR_UNAVAILABLE;
}
+ virtual aaudio_result_t standby() {
+ ALOGD("AAudioServiceEndpoint::standby() AAUDIO_ERROR_UNAVAILABLE");
+ return AAUDIO_ERROR_UNAVAILABLE;
+ }
+
+ virtual aaudio_result_t exitStandby(AudioEndpointParcelable* parcelable) {
+ ALOGD("AAudioServiceEndpoint::exitStandby() AAUDIO_ERROR_UNAVAILABLE");
+ return AAUDIO_ERROR_UNAVAILABLE;
+ }
+
/**
* @param positionFrames
* @param timeNanos
diff --git a/services/oboeservice/AAudioServiceEndpointCapture.cpp b/services/oboeservice/AAudioServiceEndpointCapture.cpp
index bc769f0..95bd4bb 100644
--- a/services/oboeservice/AAudioServiceEndpointCapture.cpp
+++ b/services/oboeservice/AAudioServiceEndpointCapture.cpp
@@ -66,8 +66,7 @@
getFramesPerBurst(), timeoutNanos);
if (result == AAUDIO_ERROR_DISCONNECTED) {
ALOGD("%s() read() returned AAUDIO_ERROR_DISCONNECTED", __func__);
- // We do not need the returned vector.
- (void) AAudioServiceEndpointShared::disconnectRegisteredStreams();
+ AAudioServiceEndpointShared::handleDisconnectRegisteredStreamsAsync();
break;
} else if (result != getFramesPerBurst()) {
ALOGW("callbackLoop() read %d / %d",
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
index b9c1260..a266d5b 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -186,37 +186,8 @@
ALOGD("%s() deviceId = %d, sessionId = %d", __func__, getDeviceId(), getSessionId());
// Create MMAP/NOIRQ buffer.
- int32_t minSizeFrames = getBufferCapacity();
- if (minSizeFrames <= 0) { // zero will get rejected
- minSizeFrames = AAUDIO_BUFFER_CAPACITY_MIN;
- }
- status = mMmapStream->createMmapBuffer(minSizeFrames, &mMmapBufferinfo);
- bool isBufferShareable = mMmapBufferinfo.flags & AUDIO_MMAP_APPLICATION_SHAREABLE;
- if (status != OK) {
- ALOGE("%s() - createMmapBuffer() failed with status %d %s",
- __func__, status, strerror(-status));
- result = AAUDIO_ERROR_UNAVAILABLE;
+ if (createMmapBuffer(&mAudioDataFileDescriptor) != AAUDIO_OK) {
goto error;
- } else {
- ALOGD("%s() createMmapBuffer() buffer_size = %d fr, burst_size %d fr"
- ", Sharable FD: %s",
- __func__,
- mMmapBufferinfo.buffer_size_frames,
- mMmapBufferinfo.burst_size_frames,
- isBufferShareable ? "Yes" : "No");
- }
-
- setBufferCapacity(mMmapBufferinfo.buffer_size_frames);
- if (!isBufferShareable) {
- // Exclusive mode can only be used by the service because the FD cannot be shared.
- int32_t audioServiceUid =
- VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(getuid()));
- if ((mMmapClient.attributionSource.uid != audioServiceUid) &&
- getSharingMode() == AAUDIO_SHARING_MODE_EXCLUSIVE) {
- ALOGW("%s() - exclusive FD cannot be used by client", __func__);
- result = AAUDIO_ERROR_UNAVAILABLE;
- goto error;
- }
}
// Get information about the stream and pass it back to the caller.
@@ -224,24 +195,17 @@
config.channel_mask, getDirection() == AAUDIO_DIRECTION_INPUT,
AAudio_isChannelIndexMask(config.channel_mask)));
- // AAudio creates a copy of this FD and retains ownership of the copy.
- // Assume that AudioFlinger will close the original shared_memory_fd.
- mAudioDataFileDescriptor.reset(dup(mMmapBufferinfo.shared_memory_fd));
- if (mAudioDataFileDescriptor.get() == -1) {
- ALOGE("%s() - could not dup shared_memory_fd", __func__);
- result = AAUDIO_ERROR_INTERNAL;
- goto error;
- }
- // Call to HAL to make sure the transport FD was able to be closed by binder.
- // This is a tricky workaround for a problem in Binder.
- // TODO:[b/192048842] When that problem is fixed we may be able to remove or change this code.
- struct audio_mmap_position position;
- mMmapStream->getMmapPosition(&position);
-
- mFramesPerBurst = mMmapBufferinfo.burst_size_frames;
setFormat(config.format);
setSampleRate(config.sample_rate);
+ // If the position is not updated while the timestamp is updated for more than a certain amount,
+ // the timestamp reported from the HAL may not be accurate. Here, a timestamp grace period is
+ // set as 5 burst size. We may want to update this value if there is any report from OEMs saying
+ // that is too short.
+ static constexpr int kTimestampGraceBurstCount = 5;
+ mTimestampGracePeriodMs = ((int64_t) kTimestampGraceBurstCount * mFramesPerBurst
+ * AAUDIO_MILLIS_PER_SECOND) / getSampleRate();
+
ALOGD("%s() actual rate = %d, channels = %d channelMask = %#x, deviceId = %d, capacity = %d\n",
__func__, getSampleRate(), getSamplesPerFrame(), getChannelMask(),
deviceId, getBufferCapacity());
@@ -315,6 +279,32 @@
return result;
}
+aaudio_result_t AAudioServiceEndpointMMAP::standby() {
+ if (mMmapStream == nullptr) {
+ return AAUDIO_ERROR_NULL;
+ }
+ aaudio_result_t result = AAudioConvert_androidToAAudioResult(mMmapStream->standby());
+ return result;
+}
+
+aaudio_result_t AAudioServiceEndpointMMAP::exitStandby(AudioEndpointParcelable* parcelable) {
+ if (mMmapStream == nullptr) {
+ return AAUDIO_ERROR_NULL;
+ }
+ mAudioDataFileDescriptor.reset();
+ aaudio_result_t result = createMmapBuffer(&mAudioDataFileDescriptor);
+ if (result == AAUDIO_OK) {
+ int32_t bytesPerFrame = calculateBytesPerFrame();
+ int32_t capacityInBytes = getBufferCapacity() * bytesPerFrame;
+ int fdIndex = parcelable->addFileDescriptor(mAudioDataFileDescriptor, capacityInBytes);
+ parcelable->mDownDataQueueParcelable.setupMemory(fdIndex, 0, capacityInBytes);
+ parcelable->mDownDataQueueParcelable.setBytesPerFrame(bytesPerFrame);
+ parcelable->mDownDataQueueParcelable.setFramesPerBurst(mFramesPerBurst);
+ parcelable->mDownDataQueueParcelable.setCapacityInFrames(getBufferCapacity());
+ }
+ return result;
+}
+
// Get free-running DSP or DMA hardware position from the HAL.
aaudio_result_t AAudioServiceEndpointMMAP::getFreeRunningPosition(int64_t *positionFrames,
int64_t *timeNanos) {
@@ -418,14 +408,133 @@
aaudio_result_t AAudioServiceEndpointMMAP::getExternalPosition(uint64_t *positionFrames,
int64_t *timeNanos)
{
- if (!mExternalPositionSupported) {
- return AAUDIO_ERROR_INVALID_STATE;
+ if (mHalExternalPositionStatus != AAUDIO_OK) {
+ return mHalExternalPositionStatus;
}
- status_t status = mMmapStream->getExternalPosition(positionFrames, timeNanos);
- if (status == INVALID_OPERATION) {
- // getExternalPosition is not supported. Set mExternalPositionSupported as false
+ uint64_t tempPositionFrames;
+ int64_t tempTimeNanos;
+ status_t status = mMmapStream->getExternalPosition(&tempPositionFrames, &tempTimeNanos);
+ if (status != OK) {
+ // getExternalPosition reports error. The HAL may not support the API. Cache the result
// so that the call will not go to the HAL next time.
- mExternalPositionSupported = false;
+ mHalExternalPositionStatus = AAudioConvert_androidToAAudioResult(status);
+ return mHalExternalPositionStatus;
}
- return AAudioConvert_androidToAAudioResult(status);
+
+ // If the HAL keeps reporting the same position or timestamp, the HAL may be having some issues
+ // to report correct external position. In that case, we will not trust the values reported from
+ // the HAL. Ideally, we may want to stop querying external position if the HAL cannot report
+ // correct position within a period. But it may not be a good idea to get system time too often.
+ // In that case, a maximum number of frozen external position is defined so that if the
+ // count of the same timestamp or position is reported by the HAL continuously, the values from
+ // the HAL will no longer be trusted.
+ static constexpr int kMaxFrozenCount = 20;
+ // If the HAL version is less than 7.0, the getPresentationPosition is an optional API.
+ // If the HAL version is 7.0 or later, the getPresentationPosition is a mandatory API.
+ // In that case, even the returned status is NO_ERROR, it doesn't indicate the returned
+ // position is a valid one. Do a simple validation, which is checking if the position is
+ // forward within half a second or not, here so that this function can return error if
+ // the validation fails. Note that we don't only apply this validation logic to HAL API
+ // less than 7.0. The reason is that there is a chance the HAL is not reporting the
+ // timestamp and position correctly.
+ if (mLastPositionFrames > tempPositionFrames) {
+ // If the position is going backwards, there must be something wrong with the HAL.
+ // In that case, we do not trust the values reported by the HAL.
+ ALOGW("%s position is going backwards, last position(%jd) current position(%jd)",
+ __func__, mLastPositionFrames, tempPositionFrames);
+ mHalExternalPositionStatus = AAUDIO_ERROR_INTERNAL;
+ return mHalExternalPositionStatus;
+ } else if (mLastPositionFrames == tempPositionFrames) {
+ if (tempTimeNanos - mTimestampNanosForLastPosition >
+ AAUDIO_NANOS_PER_MILLISECOND * mTimestampGracePeriodMs) {
+ ALOGW("%s, the reported position is not changed within %d msec. "
+ "Set the external position as not supported", __func__, mTimestampGracePeriodMs);
+ mHalExternalPositionStatus = AAUDIO_ERROR_INTERNAL;
+ return mHalExternalPositionStatus;
+ }
+ mFrozenPositionCount++;
+ } else {
+ mFrozenPositionCount = 0;
+ }
+
+ if (mTimestampNanosForLastPosition > tempTimeNanos) {
+ // If the timestamp is going backwards, there must be something wrong with the HAL.
+ // In that case, we do not trust the values reported by the HAL.
+ ALOGW("%s timestamp is going backwards, last timestamp(%jd), current timestamp(%jd)",
+ __func__, mTimestampNanosForLastPosition, tempTimeNanos);
+ mHalExternalPositionStatus = AAUDIO_ERROR_INTERNAL;
+ return mHalExternalPositionStatus;
+ } else if (mTimestampNanosForLastPosition == tempTimeNanos) {
+ mFrozenTimestampCount++;
+ } else {
+ mFrozenTimestampCount = 0;
+ }
+
+ if (mFrozenTimestampCount + mFrozenPositionCount > kMaxFrozenCount) {
+ ALOGW("%s too many frozen external position from HAL.", __func__);
+ mHalExternalPositionStatus = AAUDIO_ERROR_INTERNAL;
+ return mHalExternalPositionStatus;
+ }
+
+ mLastPositionFrames = tempPositionFrames;
+ mTimestampNanosForLastPosition = tempTimeNanos;
+
+ // Only update the timestamp and position when they looks valid.
+ *positionFrames = tempPositionFrames;
+ *timeNanos = tempTimeNanos;
+ return mHalExternalPositionStatus;
+}
+
+aaudio_result_t AAudioServiceEndpointMMAP::createMmapBuffer(
+ android::base::unique_fd* fileDescriptor)
+{
+ memset(&mMmapBufferinfo, 0, sizeof(struct audio_mmap_buffer_info));
+ int32_t minSizeFrames = getBufferCapacity();
+ if (minSizeFrames <= 0) { // zero will get rejected
+ minSizeFrames = AAUDIO_BUFFER_CAPACITY_MIN;
+ }
+ status_t status = mMmapStream->createMmapBuffer(minSizeFrames, &mMmapBufferinfo);
+ bool isBufferShareable = mMmapBufferinfo.flags & AUDIO_MMAP_APPLICATION_SHAREABLE;
+ if (status != OK) {
+ ALOGE("%s() - createMmapBuffer() failed with status %d %s",
+ __func__, status, strerror(-status));
+ return AAUDIO_ERROR_UNAVAILABLE;
+ } else {
+ ALOGD("%s() createMmapBuffer() buffer_size = %d fr, burst_size %d fr"
+ ", Sharable FD: %s",
+ __func__,
+ mMmapBufferinfo.buffer_size_frames,
+ mMmapBufferinfo.burst_size_frames,
+ isBufferShareable ? "Yes" : "No");
+ }
+
+ setBufferCapacity(mMmapBufferinfo.buffer_size_frames);
+ if (!isBufferShareable) {
+ // Exclusive mode can only be used by the service because the FD cannot be shared.
+ int32_t audioServiceUid =
+ VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(getuid()));
+ if ((mMmapClient.attributionSource.uid != audioServiceUid) &&
+ getSharingMode() == AAUDIO_SHARING_MODE_EXCLUSIVE) {
+ ALOGW("%s() - exclusive FD cannot be used by client", __func__);
+ return AAUDIO_ERROR_UNAVAILABLE;
+ }
+ }
+
+ // AAudio creates a copy of this FD and retains ownership of the copy.
+ // Assume that AudioFlinger will close the original shared_memory_fd.
+ fileDescriptor->reset(dup(mMmapBufferinfo.shared_memory_fd));
+ if (fileDescriptor->get() == -1) {
+ ALOGE("%s() - could not dup shared_memory_fd", __func__);
+ return AAUDIO_ERROR_INTERNAL;
+ }
+
+ // Call to HAL to make sure the transport FD was able to be closed by binder.
+ // This is a tricky workaround for a problem in Binder.
+ // TODO:[b/192048842] When that problem is fixed we may be able to remove or change this code.
+ struct audio_mmap_position position;
+ mMmapStream->getMmapPosition(&position);
+
+ mFramesPerBurst = mMmapBufferinfo.burst_size_frames;
+
+ return AAUDIO_OK;
}
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.h b/services/oboeservice/AAudioServiceEndpointMMAP.h
index ddfac63..3e7f2c7 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.h
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.h
@@ -64,6 +64,10 @@
aaudio_result_t stopClient(audio_port_handle_t clientHandle) override;
+ aaudio_result_t standby() override;
+
+ aaudio_result_t exitStandby(AudioEndpointParcelable* parcelable) override;
+
aaudio_result_t getFreeRunningPosition(int64_t *positionFrames, int64_t *timeNanos) override;
aaudio_result_t getTimestamp(int64_t *positionFrames, int64_t *timeNanos) override;
@@ -91,6 +95,8 @@
aaudio_result_t openWithFormat(audio_format_t audioFormat);
+ aaudio_result_t createMmapBuffer(android::base::unique_fd* fileDescriptor);
+
MonotonicCounter mFramesTransferred;
// Interface to the AudioFlinger MMAP support.
@@ -106,7 +112,12 @@
int64_t mHardwareTimeOffsetNanos = 0; // TODO get from HAL
- bool mExternalPositionSupported = true;
+ aaudio_result_t mHalExternalPositionStatus = AAUDIO_OK;
+ uint64_t mLastPositionFrames = 0;
+ int64_t mTimestampNanosForLastPosition = 0;
+ int32_t mTimestampGracePeriodMs;
+ int32_t mFrozenPositionCount = 0;
+ int32_t mFrozenTimestampCount = 0;
};
diff --git a/services/oboeservice/AAudioServiceEndpointPlay.cpp b/services/oboeservice/AAudioServiceEndpointPlay.cpp
index f590fc8..2a5939f 100644
--- a/services/oboeservice/AAudioServiceEndpointPlay.cpp
+++ b/services/oboeservice/AAudioServiceEndpointPlay.cpp
@@ -147,8 +147,7 @@
getFramesPerBurst(), timeoutNanos);
if (result == AAUDIO_ERROR_DISCONNECTED) {
ALOGD("%s() write() returned AAUDIO_ERROR_DISCONNECTED", __func__);
- // We do not need the returned vector.
- (void) AAudioServiceEndpointShared::disconnectRegisteredStreams();
+ AAudioServiceEndpointShared::handleDisconnectRegisteredStreamsAsync();
break;
} else if (result != getFramesPerBurst()) {
ALOGW("callbackLoop() wrote %d / %d",
diff --git a/services/oboeservice/AAudioServiceEndpointShared.cpp b/services/oboeservice/AAudioServiceEndpointShared.cpp
index 5af0a91..dd421fe 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.cpp
+++ b/services/oboeservice/AAudioServiceEndpointShared.cpp
@@ -214,3 +214,12 @@
}
return result;
}
+
+void AAudioServiceEndpointShared::handleDisconnectRegisteredStreamsAsync() {
+ android::sp<AAudioServiceEndpointShared> holdEndpoint(this);
+ std::thread asyncTask([holdEndpoint]() {
+ // We do not need the returned vector.
+ holdEndpoint->disconnectRegisteredStreams();
+ });
+ asyncTask.detach();
+}
diff --git a/services/oboeservice/AAudioServiceEndpointShared.h b/services/oboeservice/AAudioServiceEndpointShared.h
index 8357567..3e760c4 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.h
+++ b/services/oboeservice/AAudioServiceEndpointShared.h
@@ -69,6 +69,8 @@
aaudio_result_t stopSharingThread();
+ void handleDisconnectRegisteredStreamsAsync();
+
// An MMAP stream that is shared by multiple clients.
android::sp<AudioStreamInternal> mStreamInternal;
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index a25a791..9f48f80 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -41,6 +41,8 @@
using content::AttributionSourceState;
static const int64_t TIMEOUT_NANOS = 3LL * 1000 * 1000 * 1000;
+// If the stream is idle for more than `IDLE_TIMEOUT_NANOS`, the stream will be put into standby.
+static const int64_t IDLE_TIMEOUT_NANOS = 3e9;
/**
* Base class for streams in the service.
@@ -52,7 +54,6 @@
, mAtomicStreamTimestamp()
, mAudioService(audioService) {
mMmapClient.attributionSource = AttributionSourceState();
- mThreadEnabled = true;
}
AAudioServiceStreamBase::~AAudioServiceStreamBase() {
@@ -178,6 +179,7 @@
// Make sure this object does not get deleted before the run() method
// can protect it by making a strong pointer.
+ mCommandQueue.startWaiting();
mThreadEnabled = true;
incStrong(nullptr); // See run() method.
result = mCommandThread.start(this);
@@ -188,14 +190,15 @@
return result;
error:
- close();
+ closeAndClear();
+ mThreadEnabled = false;
+ mCommandQueue.stopWaiting();
+ mCommandThread.stop();
return result;
}
aaudio_result_t AAudioServiceStreamBase::close() {
- auto command = std::make_shared<AAudioCommand>(
- CLOSE, nullptr, true /*waitForReply*/, TIMEOUT_NANOS);
- aaudio_result_t result = mCommandQueue.sendCommand(command);
+ aaudio_result_t result = sendCommand(CLOSE, nullptr, true /*waitForReply*/, TIMEOUT_NANOS);
// Stop the command thread as the stream is closed.
mThreadEnabled = false;
@@ -213,25 +216,7 @@
// This will stop the stream, just in case it was not already stopped.
stop_l();
- aaudio_result_t result = AAUDIO_OK;
- sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
- if (endpoint == nullptr) {
- result = AAUDIO_ERROR_INVALID_STATE;
- } else {
- endpoint->unregisterStream(this);
- AAudioEndpointManager &endpointManager = AAudioEndpointManager::getInstance();
- endpointManager.closeEndpoint(endpoint);
-
- // AAudioService::closeStream() prevents two threads from closing at the same time.
- mServiceEndpoint.clear(); // endpoint will hold the pointer after this method returns.
- }
-
- setState(AAUDIO_STREAM_STATE_CLOSED);
-
- mediametrics::LogItem(mMetricsId)
- .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_CLOSE)
- .record();
- return result;
+ return closeAndClear();
}
aaudio_result_t AAudioServiceStreamBase::startDevice() {
@@ -250,9 +235,7 @@
* An AAUDIO_SERVICE_EVENT_STARTED will be sent to the client when complete.
*/
aaudio_result_t AAudioServiceStreamBase::start() {
- auto command = std::make_shared<AAudioCommand>(
- START, nullptr, true /*waitForReply*/, TIMEOUT_NANOS);
- return mCommandQueue.sendCommand(command);
+ return sendCommand(START, nullptr, true /*waitForReply*/, TIMEOUT_NANOS);
}
aaudio_result_t AAudioServiceStreamBase::start_l() {
@@ -266,6 +249,12 @@
return AAUDIO_ERROR_INVALID_STATE;
}
+ if (mStandby) {
+ ALOGW("%s() the stream is standby, return ERROR_STANDBY, "
+ "expecting the client call exitStandby before start", __func__);
+ return AAUDIO_ERROR_STANDBY;
+ }
+
mediametrics::Defer defer([&] {
mediametrics::LogItem(mMetricsId)
.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_START)
@@ -300,9 +289,7 @@
}
aaudio_result_t AAudioServiceStreamBase::pause() {
- auto command = std::make_shared<AAudioCommand>(
- PAUSE, nullptr, true /*waitForReply*/, TIMEOUT_NANOS);
- return mCommandQueue.sendCommand(command);
+ return sendCommand(PAUSE, nullptr, true /*waitForReply*/, TIMEOUT_NANOS);
}
aaudio_result_t AAudioServiceStreamBase::pause_l() {
@@ -338,9 +325,7 @@
}
aaudio_result_t AAudioServiceStreamBase::stop() {
- auto command = std::make_shared<AAudioCommand>(
- STOP, nullptr, true /*waitForReply*/, TIMEOUT_NANOS);
- return mCommandQueue.sendCommand(command);
+ return sendCommand(STOP, nullptr, true /*waitForReply*/, TIMEOUT_NANOS);
}
aaudio_result_t AAudioServiceStreamBase::stop_l() {
@@ -385,9 +370,7 @@
}
aaudio_result_t AAudioServiceStreamBase::flush() {
- auto command = std::make_shared<AAudioCommand>(
- FLUSH, nullptr, true /*waitForReply*/, TIMEOUT_NANOS);
- return mCommandQueue.sendCommand(command);
+ return sendCommand(FLUSH, nullptr, true /*waitForReply*/, TIMEOUT_NANOS);
}
aaudio_result_t AAudioServiceStreamBase::flush_l() {
@@ -419,6 +402,7 @@
android::sp<AAudioServiceStreamBase> holdStream(this);
TimestampScheduler timestampScheduler;
int64_t nextTime;
+ int64_t standbyTime = AudioClock::getNanoseconds() + IDLE_TIMEOUT_NANOS;
// Balance the incStrong from when the thread was launched.
holdStream->decStrong(nullptr);
@@ -430,8 +414,8 @@
while (mThreadEnabled.load()) {
loopCount++;
int64_t timeoutNanos = -1;
- if (isRunning()) {
- timeoutNanos = nextTime - AudioClock::getNanoseconds();
+ if (isRunning() || (isIdle_l() && !isStandby_l())) {
+ timeoutNanos = (isRunning() ? nextTime : standbyTime) - AudioClock::getNanoseconds();
timeoutNanos = std::max<int64_t>(0, timeoutNanos);
}
@@ -450,6 +434,9 @@
nextTime = timestampScheduler.nextAbsoluteTime();
}
}
+ if (isIdle_l() && AudioClock::getNanoseconds() >= standbyTime) {
+ standby_l();
+ }
if (command != nullptr) {
std::scoped_lock<std::mutex> _commandLock(command->lock);
@@ -462,9 +449,11 @@
break;
case PAUSE:
command->result = pause_l();
+ standbyTime = AudioClock::getNanoseconds() + IDLE_TIMEOUT_NANOS;
break;
case STOP:
command->result = stop_l();
+ standbyTime = AudioClock::getNanoseconds() + IDLE_TIMEOUT_NANOS;
break;
case FLUSH:
command->result = flush_l();
@@ -499,6 +488,12 @@
: getDescription_l(param->mParcelable);
}
break;
+ case EXIT_STANDBY: {
+ ExitStandbyParam *param = (ExitStandbyParam *) command->parameter.get();
+ command->result = param == nullptr ? AAUDIO_ERROR_ILLEGAL_ARGUMENT
+ : exitStandby_l(param->mParcelable);
+ standbyTime = AudioClock::getNanoseconds() + IDLE_TIMEOUT_NANOS;
+ } break;
default:
ALOGE("Invalid command op code: %d", command->operationCode);
break;
@@ -514,8 +509,7 @@
}
void AAudioServiceStreamBase::disconnect() {
- auto command = std::make_shared<AAudioCommand>(DISCONNECT);
- mCommandQueue.sendCommand(command);
+ sendCommand(DISCONNECT);
}
void AAudioServiceStreamBase::disconnect_l() {
@@ -533,12 +527,10 @@
aaudio_result_t AAudioServiceStreamBase::registerAudioThread(pid_t clientThreadId, int priority) {
const pid_t ownerPid = IPCThreadState::self()->getCallingPid(); // TODO review
- auto command = std::make_shared<AAudioCommand>(
- REGISTER_AUDIO_THREAD,
+ return sendCommand(REGISTER_AUDIO_THREAD,
std::make_shared<RegisterAudioThreadParam>(ownerPid, clientThreadId, priority),
true /*waitForReply*/,
TIMEOUT_NANOS);
- return mCommandQueue.sendCommand(command);
}
aaudio_result_t AAudioServiceStreamBase::registerAudioThread_l(
@@ -561,12 +553,10 @@
}
aaudio_result_t AAudioServiceStreamBase::unregisterAudioThread(pid_t clientThreadId) {
- auto command = std::make_shared<AAudioCommand>(
- UNREGISTER_AUDIO_THREAD,
+ return sendCommand(UNREGISTER_AUDIO_THREAD,
std::make_shared<UnregisterAudioThreadParam>(clientThreadId),
true /*waitForReply*/,
TIMEOUT_NANOS);
- return mCommandQueue.sendCommand(command);
}
aaudio_result_t AAudioServiceStreamBase::unregisterAudioThread_l(pid_t clientThreadId) {
@@ -682,12 +672,11 @@
* used to communicate with the underlying HAL or Service.
*/
aaudio_result_t AAudioServiceStreamBase::getDescription(AudioEndpointParcelable &parcelable) {
- auto command = std::make_shared<AAudioCommand>(
+ return sendCommand(
GET_DESCRIPTION,
std::make_shared<GetDescriptionParam>(&parcelable),
true /*waitForReply*/,
TIMEOUT_NANOS);
- return mCommandQueue.sendCommand(command);
}
aaudio_result_t AAudioServiceStreamBase::getDescription_l(AudioEndpointParcelable* parcelable) {
@@ -704,6 +693,45 @@
return getAudioDataDescription_l(parcelable);
}
+aaudio_result_t AAudioServiceStreamBase::exitStandby(AudioEndpointParcelable *parcelable) {
+ auto command = std::make_shared<AAudioCommand>(
+ EXIT_STANDBY,
+ std::make_shared<ExitStandbyParam>(parcelable),
+ true /*waitForReply*/,
+ TIMEOUT_NANOS);
+ return mCommandQueue.sendCommand(command);
+}
+
void AAudioServiceStreamBase::onVolumeChanged(float volume) {
sendServiceEvent(AAUDIO_SERVICE_EVENT_VOLUME, volume);
}
+
+aaudio_result_t AAudioServiceStreamBase::sendCommand(aaudio_command_opcode opCode,
+ std::shared_ptr<AAudioCommandParam> param,
+ bool waitForReply,
+ int64_t timeoutNanos) {
+ return mCommandQueue.sendCommand(std::make_shared<AAudioCommand>(
+ opCode, param, waitForReply, timeoutNanos));
+}
+
+aaudio_result_t AAudioServiceStreamBase::closeAndClear() {
+ aaudio_result_t result = AAUDIO_OK;
+ sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
+ if (endpoint == nullptr) {
+ result = AAUDIO_ERROR_INVALID_STATE;
+ } else {
+ endpoint->unregisterStream(this);
+ AAudioEndpointManager &endpointManager = AAudioEndpointManager::getInstance();
+ endpointManager.closeEndpoint(endpoint);
+
+ // AAudioService::closeStream() prevents two threads from closing at the same time.
+ mServiceEndpoint.clear(); // endpoint will hold the pointer after this method returns.
+ }
+
+ setState(AAUDIO_STREAM_STATE_CLOSED);
+
+ mediametrics::LogItem(mMetricsId)
+ .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_CLOSE)
+ .record();
+ return result;
+}
diff --git a/services/oboeservice/AAudioServiceStreamBase.h b/services/oboeservice/AAudioServiceStreamBase.h
index aa8e8cf..b2ba725 100644
--- a/services/oboeservice/AAudioServiceStreamBase.h
+++ b/services/oboeservice/AAudioServiceStreamBase.h
@@ -116,6 +116,11 @@
*/
aaudio_result_t flush() EXCLUDES(mLock);
+ /**
+ * Exit standby mode. The MMAP buffer will be reallocated.
+ */
+ aaudio_result_t exitStandby(AudioEndpointParcelable *parcelable) EXCLUDES(mLock);
+
virtual aaudio_result_t startClient(const android::AudioClient& client,
const audio_attributes_t *attr __unused,
audio_port_handle_t *clientHandle __unused) {
@@ -314,6 +319,33 @@
mDisconnected = flag;
}
+ virtual aaudio_result_t standby_l() REQUIRES(mLock) {
+ return AAUDIO_ERROR_UNAVAILABLE;
+ }
+ class ExitStandbyParam : public AAudioCommandParam {
+ public:
+ ExitStandbyParam(AudioEndpointParcelable* parcelable)
+ : AAudioCommandParam(), mParcelable(parcelable) { }
+ ~ExitStandbyParam() = default;
+
+ AudioEndpointParcelable* mParcelable;
+ };
+ virtual aaudio_result_t exitStandby_l(
+ AudioEndpointParcelable* parcelable __unused) REQUIRES(mLock) {
+ return AAUDIO_ERROR_UNAVAILABLE;
+ }
+ bool isStandby_l() const REQUIRES(mLock) {
+ return mStandby;
+ }
+ void setStandby_l(bool standby) REQUIRES(mLock) {
+ mStandby = standby;
+ }
+
+ bool isIdle_l() const REQUIRES(mLock) {
+ return mState == AAUDIO_STREAM_STATE_OPEN || mState == AAUDIO_STREAM_STATE_PAUSED
+ || mState == AAUDIO_STREAM_STATE_STOPPED;
+ }
+
pid_t mRegisteredClientThread = ILLEGAL_THREAD_ID;
std::mutex mUpMessageQueueLock;
@@ -329,6 +361,7 @@
REGISTER_AUDIO_THREAD,
UNREGISTER_AUDIO_THREAD,
GET_DESCRIPTION,
+ EXIT_STANDBY,
};
AAudioThread mCommandThread;
std::atomic<bool> mThreadEnabled{false};
@@ -366,6 +399,13 @@
aaudio_result_t sendServiceEvent(aaudio_service_event_t event,
double dataDouble);
+ aaudio_result_t sendCommand(aaudio_command_opcode opCode,
+ std::shared_ptr<AAudioCommandParam> param = nullptr,
+ bool waitForReply = false,
+ int64_t timeoutNanos = 0);
+
+ aaudio_result_t closeAndClear();
+
/**
* @return true if the queue is getting full.
*/
@@ -384,6 +424,8 @@
bool mDisconnected GUARDED_BY(mLock) {false};
+ bool mStandby GUARDED_BY(mLock) = false;
+
protected:
// Locking order is important.
// Acquire mLock before acquiring AAudioServiceEndpoint::mLockStreams
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.cpp b/services/oboeservice/AAudioServiceStreamMMAP.cpp
index 05b7f7d..ec9b2e2 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.cpp
+++ b/services/oboeservice/AAudioServiceStreamMMAP.cpp
@@ -117,6 +117,35 @@
return result;
}
+aaudio_result_t AAudioServiceStreamMMAP::standby_l() {
+ sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
+ if (endpoint == nullptr) {
+ ALOGE("%s() has no endpoint", __func__);
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
+ aaudio_result_t result = endpoint->standby();
+ if (result == AAUDIO_OK) {
+ setStandby_l(true);
+ }
+ return result;
+}
+
+aaudio_result_t AAudioServiceStreamMMAP::exitStandby_l(AudioEndpointParcelable* parcelable) {
+ sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
+ if (endpoint == nullptr) {
+ ALOGE("%s() has no endpoint", __func__);
+ return AAUDIO_ERROR_INVALID_STATE;
+ }
+ aaudio_result_t result = endpoint->exitStandby(parcelable);
+ if (result == AAUDIO_OK) {
+ setStandby_l(false);
+ } else {
+ ALOGE("%s failed, result %d, disconnecting stream.", __func__, result);
+ disconnect_l();
+ }
+ return result;
+}
+
aaudio_result_t AAudioServiceStreamMMAP::startClient(const android::AudioClient& client,
const audio_attributes_t *attr,
audio_port_handle_t *clientHandle) {
@@ -167,7 +196,6 @@
// If it fails, get timestamp that was written by getFreeRunningPosition()
aaudio_result_t AAudioServiceStreamMMAP::getHardwareTimestamp_l(int64_t *positionFrames,
int64_t *timeNanos) {
-
sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
if (endpoint == nullptr) {
ALOGE("%s() has no endpoint", __func__);
@@ -176,17 +204,17 @@
sp<AAudioServiceEndpointMMAP> serviceEndpointMMAP =
static_cast<AAudioServiceEndpointMMAP *>(endpoint.get());
- // Disable this code temporarily because the HAL is not returning
- // a useful result.
-#if 0
uint64_t position;
- if (serviceEndpointMMAP->getExternalPosition(&position, timeNanos) == AAUDIO_OK) {
- ALOGD("%s() getExternalPosition() says pos = %" PRIi64 ", time = %" PRIi64,
+ aaudio_result_t result = serviceEndpointMMAP->getExternalPosition(&position, timeNanos);
+ if (result == AAUDIO_OK) {
+ ALOGV("%s() getExternalPosition() says pos = %" PRIi64 ", time = %" PRIi64,
__func__, position, *timeNanos);
*positionFrames = (int64_t) position;
return AAUDIO_OK;
- } else
-#endif
+ } else {
+ ALOGV("%s() getExternalPosition() returns error %d", __func__, result);
+ }
+
if (mAtomicStreamTimestamp.isValid()) {
Timestamp timestamp = mAtomicStreamTimestamp.read();
*positionFrames = timestamp.getPosition();
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.h b/services/oboeservice/AAudioServiceStreamMMAP.h
index 28da120..cd8c91e 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.h
+++ b/services/oboeservice/AAudioServiceStreamMMAP.h
@@ -71,6 +71,10 @@
aaudio_result_t stop_l() REQUIRES(mLock) override;
+ aaudio_result_t standby_l() REQUIRES(mLock) override;
+
+ aaudio_result_t exitStandby_l(AudioEndpointParcelable* parcelable) REQUIRES(mLock) override;
+
aaudio_result_t getAudioDataDescription_l(
AudioEndpointParcelable* parcelable) REQUIRES(mLock) override;
diff --git a/services/oboeservice/fuzzer/oboeservice_fuzzer.cpp b/services/oboeservice/fuzzer/oboeservice_fuzzer.cpp
index 17e8d36..5e48955 100644
--- a/services/oboeservice/fuzzer/oboeservice_fuzzer.cpp
+++ b/services/oboeservice/fuzzer/oboeservice_fuzzer.cpp
@@ -180,6 +180,11 @@
return AAUDIO_ERROR_UNAVAILABLE;
}
+ aaudio_result_t exitStandby(aaudio_handle_t streamHandle UNUSED_PARAM,
+ AudioEndpointParcelable &parcelable UNUSED_PARAM) override {
+ return AAUDIO_ERROR_UNAVAILABLE;
+ }
+
void onStreamChange(aaudio_handle_t handle, int32_t opcode, int32_t value) {}
int getDeathCount() { return mDeathCount; }
diff --git a/services/tuner/TunerFrontend.cpp b/services/tuner/TunerFrontend.cpp
index e86e8e1..5116305 100644
--- a/services/tuner/TunerFrontend.cpp
+++ b/services/tuner/TunerFrontend.cpp
@@ -115,16 +115,6 @@
return mFrontend->setLnb(static_cast<TunerLnb*>(lnb.get())->getId());
}
-::ndk::ScopedAStatus TunerFrontend::setLna(bool bEnable) {
- if (mFrontend == nullptr) {
- ALOGD("IFrontend is not initialized");
- return ::ndk::ScopedAStatus::fromServiceSpecificError(
- static_cast<int32_t>(Result::UNAVAILABLE));
- }
-
- return mFrontend->setLna(bEnable);
-}
-
::ndk::ScopedAStatus TunerFrontend::linkCiCamToFrontend(int32_t ciCamId, int32_t* _aidl_return) {
if (mFrontend == nullptr) {
ALOGD("IFrontend is not initialized");
@@ -174,6 +164,38 @@
return ::ndk::ScopedAStatus::ok();
}
+::ndk::ScopedAStatus TunerFrontend::getHardwareInfo(std::string* _aidl_return) {
+ if (mFrontend == nullptr) {
+ ALOGD("IFrontend is not initialized");
+ return ::ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(Result::UNAVAILABLE));
+ }
+
+ return mFrontend->getHardwareInfo(_aidl_return);
+}
+
+::ndk::ScopedAStatus TunerFrontend::removeOutputPid(int32_t in_pid) {
+ if (mFrontend == nullptr) {
+ ALOGD("IFrontend is not initialized");
+ return ::ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(Result::UNAVAILABLE));
+ }
+
+ return mFrontend->removeOutputPid(in_pid);
+}
+
+::ndk::ScopedAStatus TunerFrontend::getFrontendStatusReadiness(
+ const std::vector<FrontendStatusType>& in_statusTypes,
+ std::vector<FrontendStatusReadiness>* _aidl_return) {
+ if (mFrontend == nullptr) {
+ ALOGD("IFrontend is not initialized");
+ return ::ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(Result::UNAVAILABLE));
+ }
+
+ return mFrontend->getFrontendStatusReadiness(in_statusTypes, _aidl_return);
+}
+
/////////////// FrontendCallback ///////////////////////
::ndk::ScopedAStatus TunerFrontend::FrontendCallback::onEvent(FrontendEventType frontendEventType) {
ALOGV("FrontendCallback::onEvent, type=%d", frontendEventType);
diff --git a/services/tuner/TunerFrontend.h b/services/tuner/TunerFrontend.h
index 417d969..da471fb 100644
--- a/services/tuner/TunerFrontend.h
+++ b/services/tuner/TunerFrontend.h
@@ -30,6 +30,7 @@
using ::aidl::android::hardware::tv::tuner::FrontendScanType;
using ::aidl::android::hardware::tv::tuner::FrontendSettings;
using ::aidl::android::hardware::tv::tuner::FrontendStatus;
+using ::aidl::android::hardware::tv::tuner::FrontendStatusReadiness;
using ::aidl::android::hardware::tv::tuner::FrontendStatusType;
using ::aidl::android::hardware::tv::tuner::IFrontend;
using ::aidl::android::hardware::tv::tuner::IFrontendCallback;
@@ -56,13 +57,17 @@
FrontendScanType in_frontendScanType) override;
::ndk::ScopedAStatus stopScan() override;
::ndk::ScopedAStatus setLnb(const shared_ptr<ITunerLnb>& in_lnb) override;
- ::ndk::ScopedAStatus setLna(bool in_bEnable) override;
::ndk::ScopedAStatus linkCiCamToFrontend(int32_t in_ciCamId, int32_t* _aidl_return) override;
::ndk::ScopedAStatus unlinkCiCamToFrontend(int32_t in_ciCamId) override;
::ndk::ScopedAStatus close() override;
::ndk::ScopedAStatus getStatus(const vector<FrontendStatusType>& in_statusTypes,
vector<FrontendStatus>* _aidl_return) override;
::ndk::ScopedAStatus getFrontendId(int32_t* _aidl_return) override;
+ ::ndk::ScopedAStatus getHardwareInfo(std::string* _aidl_return) override;
+ ::ndk::ScopedAStatus removeOutputPid(int32_t in_pid) override;
+ ::ndk::ScopedAStatus getFrontendStatusReadiness(
+ const std::vector<FrontendStatusType>& in_statusTypes,
+ std::vector<FrontendStatusReadiness>* _aidl_return) override;
struct FrontendCallback : public BnFrontendCallback {
FrontendCallback(const shared_ptr<ITunerFrontendCallback> tunerFrontendCallback)
diff --git a/services/tuner/TunerService.cpp b/services/tuner/TunerService.cpp
index 36e4cd1..4833aaf 100644
--- a/services/tuner/TunerService.cpp
+++ b/services/tuner/TunerService.cpp
@@ -260,6 +260,38 @@
return ::ndk::ScopedAStatus::ok();
}
+::ndk::ScopedAStatus TunerService::setLna(bool bEnable) {
+ if (!hasITuner()) {
+ ALOGD("get ITuner failed");
+ return ::ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(Result::UNAVAILABLE));
+ }
+
+ return mTuner->setLna(bEnable);
+}
+
+::ndk::ScopedAStatus TunerService::setMaxNumberOfFrontends(FrontendType in_frontendType,
+ int32_t in_maxNumber) {
+ if (!hasITuner()) {
+ ALOGD("get ITuner failed");
+ return ::ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(Result::UNAVAILABLE));
+ }
+
+ return mTuner->setMaxNumberOfFrontends(in_frontendType, in_maxNumber);
+}
+
+::ndk::ScopedAStatus TunerService::getMaxNumberOfFrontends(FrontendType in_frontendType,
+ int32_t* _aidl_return) {
+ if (!hasITuner()) {
+ ALOGD("get ITuner failed");
+ return ::ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(Result::UNAVAILABLE));
+ }
+
+ return mTuner->getMaxNumberOfFrontends(in_frontendType, _aidl_return);
+}
+
string TunerService::addFilterToShared(const shared_ptr<TunerFilter>& sharedFilter) {
Mutex::Autolock _l(mSharedFiltersLock);
diff --git a/services/tuner/TunerService.h b/services/tuner/TunerService.h
index 7bf50b6..7fc2aa4 100644
--- a/services/tuner/TunerService.h
+++ b/services/tuner/TunerService.h
@@ -33,6 +33,7 @@
using ::aidl::android::hardware::tv::tuner::DemuxFilterEvent;
using ::aidl::android::hardware::tv::tuner::DemuxFilterStatus;
using ::aidl::android::hardware::tv::tuner::FrontendInfo;
+using ::aidl::android::hardware::tv::tuner::FrontendType;
using ::aidl::android::hardware::tv::tuner::ITuner;
using ::aidl::android::media::tv::tuner::BnTunerService;
using ::aidl::android::media::tv::tuner::ITunerDemux;
@@ -76,6 +77,11 @@
::ndk::ScopedAStatus openSharedFilter(const string& in_filterToken,
const shared_ptr<ITunerFilterCallback>& in_cb,
shared_ptr<ITunerFilter>* _aidl_return) override;
+ ::ndk::ScopedAStatus setLna(bool in_bEnable) override;
+ ::ndk::ScopedAStatus setMaxNumberOfFrontends(FrontendType in_frontendType,
+ int32_t in_maxNumber) override;
+ ::ndk::ScopedAStatus getMaxNumberOfFrontends(FrontendType in_frontendType,
+ int32_t* _aidl_return) override;
string addFilterToShared(const shared_ptr<TunerFilter>& sharedFilter);
void removeSharedFilter(const shared_ptr<TunerFilter>& sharedFilter);
diff --git a/services/tuner/aidl/android/media/tv/tuner/ITunerFrontend.aidl b/services/tuner/aidl/android/media/tv/tuner/ITunerFrontend.aidl
index 771a647..0493f05 100644
--- a/services/tuner/aidl/android/media/tv/tuner/ITunerFrontend.aidl
+++ b/services/tuner/aidl/android/media/tv/tuner/ITunerFrontend.aidl
@@ -19,6 +19,7 @@
import android.hardware.tv.tuner.FrontendScanType;
import android.hardware.tv.tuner.FrontendSettings;
import android.hardware.tv.tuner.FrontendStatus;
+import android.hardware.tv.tuner.FrontendStatusReadiness;
import android.hardware.tv.tuner.FrontendStatusType;
import android.media.tv.tuner.ITunerFrontendCallback;
import android.media.tv.tuner.ITunerLnb;
@@ -69,13 +70,6 @@
void setLnb(in ITunerLnb lnb);
/**
- * Enable or Disable Low Noise Amplifier (LNA).
- *
- * @param bEnable enable Lna or not.
- */
- void setLna(in boolean bEnable);
-
- /**
* Link Frontend to the cicam with given id.
*
* @return lts id
@@ -101,4 +95,19 @@
* Gets the id of the frontend.
*/
int getFrontendId();
+
+ /**
+ * Request hardware information about the frontend.
+ */
+ String getHardwareInfo();
+
+ /**
+ * Filter out unnecessary PID from frontend output.
+ */
+ void removeOutputPid(int pid);
+
+ /**
+ * Gets FrontendStatus’ readiness statuses for given status types.
+ */
+ FrontendStatusReadiness[] getFrontendStatusReadiness(in FrontendStatusType[] statusTypes);
}
diff --git a/services/tuner/aidl/android/media/tv/tuner/ITunerService.aidl b/services/tuner/aidl/android/media/tv/tuner/ITunerService.aidl
index e6a1a5c..b8084ab 100644
--- a/services/tuner/aidl/android/media/tv/tuner/ITunerService.aidl
+++ b/services/tuner/aidl/android/media/tv/tuner/ITunerService.aidl
@@ -18,6 +18,7 @@
import android.hardware.tv.tuner.DemuxCapabilities;
import android.hardware.tv.tuner.FrontendInfo;
+import android.hardware.tv.tuner.FrontendType;
import android.media.tv.tuner.ITunerDemux;
import android.media.tv.tuner.ITunerDescrambler;
import android.media.tv.tuner.ITunerFilter;
@@ -104,4 +105,29 @@
* @return a newly created ITunerFilter interface.
*/
ITunerFilter openSharedFilter(in String filterToken, in ITunerFilterCallback cb);
+
+ /**
+ * Enable or Disable Low Noise Amplifier (LNA).
+ *
+ * @param bEnable enable Lna or not.
+ */
+ void setLna(in boolean bEnable);
+
+ /**
+ * Set the maximum usable frontends number of a given frontend type. It's used by client
+ * to enable or disable frontends when cable connection status is changed by user.
+ *
+ * @param frontendType the frontend type which the maximum usable number will be set.
+ * @param maxNumber the new maximum usable number.
+ */
+ void setMaxNumberOfFrontends(in FrontendType frontendType, in int maxNumber);
+
+ /**
+ * Get the maximum usable frontends number of a given frontend type.
+ *
+ * @param frontendType the frontend type which the maximum usable number will be queried.
+ *
+ * @return the maximum usable number of the queried frontend type.
+ */
+ int getMaxNumberOfFrontends(in FrontendType frontendType);
}
diff --git a/services/tuner/hidl/TunerHidlFilter.cpp b/services/tuner/hidl/TunerHidlFilter.cpp
index 7b76093..a5bbf39 100644
--- a/services/tuner/hidl/TunerHidlFilter.cpp
+++ b/services/tuner/hidl/TunerHidlFilter.cpp
@@ -29,6 +29,7 @@
#include "TunerHidlService.h"
using ::aidl::android::hardware::tv::tuner::AudioExtraMetaData;
+using ::aidl::android::hardware::tv::tuner::AudioStreamType;
using ::aidl::android::hardware::tv::tuner::Constant;
using ::aidl::android::hardware::tv::tuner::DemuxAlpFilterSettings;
using ::aidl::android::hardware::tv::tuner::DemuxAlpFilterSettingsFilterSettings;
@@ -604,7 +605,11 @@
bool TunerHidlFilter::getHidlAvStreamType(const AvStreamType avStreamType, HidlAvStreamType& type) {
if (isAudioFilter()) {
- type.audio(static_cast<HidlAudioStreamType>(avStreamType.get<AvStreamType::audio>()));
+ AudioStreamType audio = avStreamType.get<AvStreamType::audio>();
+ if (static_cast<int32_t>(audio) > static_cast<int32_t>(HidlAudioStreamType::DRA)) {
+ return false;
+ }
+ type.audio(static_cast<HidlAudioStreamType>(audio));
return true;
}
@@ -1036,12 +1041,16 @@
media.streamId = static_cast<int32_t>(mediaEvent.streamId);
media.isPtsPresent = mediaEvent.isPtsPresent;
media.pts = static_cast<int64_t>(mediaEvent.pts);
+ media.isDtsPresent = false;
+ media.dts = static_cast<int64_t>(-1);
media.dataLength = static_cast<int64_t>(mediaEvent.dataLength);
media.offset = static_cast<int64_t>(mediaEvent.offset);
media.isSecureMemory = mediaEvent.isSecureMemory;
media.avDataId = static_cast<int64_t>(mediaEvent.avDataId);
media.mpuSequenceNumber = static_cast<int32_t>(mediaEvent.mpuSequenceNumber);
media.isPesPrivateData = mediaEvent.isPesPrivateData;
+ media.scIndexMask.set<DemuxFilterScIndexMask::scIndex>(
+ static_cast<int32_t>(DemuxScIndex::UNDEFINED));
if (mediaEvent.extraMetaData.getDiscriminator() ==
HidlDemuxFilterMediaEvent::ExtraMetaData::hidl_discriminator::audio) {
@@ -1078,7 +1087,7 @@
section.tableId = static_cast<int32_t>(sectionEvent.tableId);
section.version = static_cast<int32_t>(sectionEvent.version);
section.sectionNum = static_cast<int32_t>(sectionEvent.sectionNum);
- section.dataLength = static_cast<int32_t>(sectionEvent.dataLength);
+ section.dataLength = static_cast<int64_t>(sectionEvent.dataLength);
DemuxFilterEvent filterEvent;
filterEvent.set<DemuxFilterEvent::section>(move(section));
@@ -1186,6 +1195,7 @@
DemuxFilterDownloadEvent download;
download.itemId = static_cast<int32_t>(downloadEvent.itemId);
+ download.downloadId = -1;
download.itemFragmentIndex = static_cast<int32_t>(downloadEvent.itemFragmentIndex);
download.mpuSequenceNumber = static_cast<int32_t>(downloadEvent.mpuSequenceNumber);
download.lastItemFragmentIndex = static_cast<int32_t>(downloadEvent.lastItemFragmentIndex);
diff --git a/services/tuner/hidl/TunerHidlFrontend.cpp b/services/tuner/hidl/TunerHidlFrontend.cpp
index 1f28406..03957f3 100644
--- a/services/tuner/hidl/TunerHidlFrontend.cpp
+++ b/services/tuner/hidl/TunerHidlFrontend.cpp
@@ -22,6 +22,7 @@
#include <aidl/android/hardware/tv/tuner/Result.h>
#include "TunerHidlLnb.h"
+#include "TunerHidlService.h"
using ::aidl::android::hardware::tv::tuner::FrontendAnalogSettings;
using ::aidl::android::hardware::tv::tuner::FrontendAnalogSifStandard;
@@ -309,21 +310,6 @@
return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(status));
}
-::ndk::ScopedAStatus TunerHidlFrontend::setLna(bool bEnable) {
- if (mFrontend == nullptr) {
- ALOGD("IFrontend is not initialized");
- return ::ndk::ScopedAStatus::fromServiceSpecificError(
- static_cast<int32_t>(Result::UNAVAILABLE));
- }
-
- HidlResult status = mFrontend->setLna(bEnable);
- if (status == HidlResult::SUCCESS) {
- return ::ndk::ScopedAStatus::ok();
- }
-
- return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(status));
-}
-
::ndk::ScopedAStatus TunerHidlFrontend::linkCiCamToFrontend(int32_t ciCamId,
int32_t* _aidl_return) {
if (mFrontend_1_1 == nullptr) {
@@ -369,6 +355,8 @@
static_cast<int32_t>(Result::UNAVAILABLE));
}
+ TunerHidlService::getTunerService()->removeFrontend(this->ref<TunerHidlFrontend>());
+
HidlResult status = mFrontend->close();
mFrontend = nullptr;
mFrontend_1_1 = nullptr;
@@ -434,6 +422,34 @@
return ::ndk::ScopedAStatus::ok();
}
+::ndk::ScopedAStatus TunerHidlFrontend::getHardwareInfo(std::string* _aidl_return) {
+ _aidl_return->clear();
+ return ::ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(Result::UNAVAILABLE));
+}
+
+::ndk::ScopedAStatus TunerHidlFrontend::removeOutputPid(int32_t /* in_pid */) {
+ return ::ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(Result::UNAVAILABLE));
+}
+
+::ndk::ScopedAStatus TunerHidlFrontend::getFrontendStatusReadiness(
+ const std::vector<FrontendStatusType>& /* in_statusTypes */,
+ std::vector<FrontendStatusReadiness>* _aidl_return) {
+ _aidl_return->clear();
+ return ::ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(Result::UNAVAILABLE));
+}
+
+void TunerHidlFrontend::setLna(bool bEnable) {
+ if (mFrontend == nullptr) {
+ ALOGD("IFrontend is not initialized");
+ return;
+ }
+
+ mFrontend->setLna(bEnable);
+}
+
/////////////// FrontendCallback ///////////////////////
Return<void> TunerHidlFrontend::FrontendCallback::onEvent(HidlFrontendEventType frontendEventType) {
ALOGV("FrontendCallback::onEvent, type=%d", frontendEventType);
diff --git a/services/tuner/hidl/TunerHidlFrontend.h b/services/tuner/hidl/TunerHidlFrontend.h
index 6a3a04a..f698655 100644
--- a/services/tuner/hidl/TunerHidlFrontend.h
+++ b/services/tuner/hidl/TunerHidlFrontend.h
@@ -32,6 +32,7 @@
using ::aidl::android::hardware::tv::tuner::FrontendScanType;
using ::aidl::android::hardware::tv::tuner::FrontendSettings;
using ::aidl::android::hardware::tv::tuner::FrontendStatus;
+using ::aidl::android::hardware::tv::tuner::FrontendStatusReadiness;
using ::aidl::android::hardware::tv::tuner::FrontendStatusType;
using ::android::sp;
using ::android::hardware::hidl_vec;
@@ -76,13 +77,19 @@
FrontendScanType in_frontendScanType) override;
::ndk::ScopedAStatus stopScan() override;
::ndk::ScopedAStatus setLnb(const shared_ptr<ITunerLnb>& in_lnb) override;
- ::ndk::ScopedAStatus setLna(bool in_bEnable) override;
::ndk::ScopedAStatus linkCiCamToFrontend(int32_t in_ciCamId, int32_t* _aidl_return) override;
::ndk::ScopedAStatus unlinkCiCamToFrontend(int32_t in_ciCamId) override;
::ndk::ScopedAStatus close() override;
::ndk::ScopedAStatus getStatus(const vector<FrontendStatusType>& in_statusTypes,
vector<FrontendStatus>* _aidl_return) override;
::ndk::ScopedAStatus getFrontendId(int32_t* _aidl_return) override;
+ ::ndk::ScopedAStatus getHardwareInfo(std::string* _aidl_return) override;
+ ::ndk::ScopedAStatus removeOutputPid(int32_t in_pid) override;
+ ::ndk::ScopedAStatus getFrontendStatusReadiness(
+ const std::vector<FrontendStatusType>& in_statusTypes,
+ std::vector<FrontendStatusReadiness>* _aidl_return) override;
+
+ void setLna(bool in_bEnable);
struct FrontendCallback : public HidlIFrontendCallback {
FrontendCallback(const shared_ptr<ITunerFrontendCallback> tunerFrontendCallback)
diff --git a/services/tuner/hidl/TunerHidlService.cpp b/services/tuner/hidl/TunerHidlService.cpp
index f4b0cde..6f55f1e 100644
--- a/services/tuner/hidl/TunerHidlService.cpp
+++ b/services/tuner/hidl/TunerHidlService.cpp
@@ -74,7 +74,10 @@
updateTunerResources();
}
-TunerHidlService::~TunerHidlService() {}
+TunerHidlService::~TunerHidlService() {
+ mOpenedFrontends.clear();
+ mLnaStatus = -1;
+}
binder_status_t TunerHidlService::instantiate() {
if (HidlITuner::getService() == nullptr) {
@@ -237,7 +240,17 @@
if (status != HidlResult::SUCCESS) {
return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(status));
}
- *_aidl_return = ::ndk::SharedRefBase::make<TunerHidlFrontend>(frontend, id);
+
+ shared_ptr<TunerHidlFrontend> tunerFrontend =
+ ::ndk::SharedRefBase::make<TunerHidlFrontend>(frontend, id);
+ if (mLnaStatus != -1) {
+ tunerFrontend->setLna(mLnaStatus == 1);
+ }
+ {
+ Mutex::Autolock _l(mOpenedFrontendsLock);
+ mOpenedFrontends.insert(tunerFrontend);
+ }
+ *_aidl_return = tunerFrontend;
return ::ndk::ScopedAStatus::ok();
}
@@ -355,6 +368,38 @@
return ::ndk::ScopedAStatus::ok();
}
+::ndk::ScopedAStatus TunerHidlService::setLna(bool bEnable) {
+ if (!hasITuner()) {
+ ALOGE("get ITuner failed");
+ return ::ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(Result::UNAVAILABLE));
+ }
+
+ mLnaStatus = bEnable ? 1 : 0;
+
+ {
+ Mutex::Autolock _l(mOpenedFrontendsLock);
+ for (auto it = mOpenedFrontends.begin(); it != mOpenedFrontends.end(); ++it) {
+ (*it)->setLna(mLnaStatus == 1);
+ }
+ }
+
+ return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlService::setMaxNumberOfFrontends(FrontendType /* in_frontendType */,
+ int32_t /* in_maxNumber */) {
+ return ::ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(Result::UNAVAILABLE));
+}
+
+::ndk::ScopedAStatus TunerHidlService::getMaxNumberOfFrontends(FrontendType /* in_frontendType */,
+ int32_t* _aidl_return) {
+ *_aidl_return = -1;
+ return ::ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(Result::UNAVAILABLE));
+}
+
string TunerHidlService::addFilterToShared(const shared_ptr<TunerHidlFilter>& sharedFilter) {
Mutex::Autolock _l(mSharedFiltersLock);
@@ -372,6 +417,16 @@
mSharedFilters.erase(to_string(reinterpret_cast<std::uintptr_t>(sharedFilter.get())));
}
+void TunerHidlService::removeFrontend(const shared_ptr<TunerHidlFrontend>& frontend) {
+ Mutex::Autolock _l(mOpenedFrontendsLock);
+ for (auto it = mOpenedFrontends.begin(); it != mOpenedFrontends.end(); ++it) {
+ if (it->get() == frontend.get()) {
+ mOpenedFrontends.erase(it);
+ break;
+ }
+ }
+}
+
void TunerHidlService::updateTunerResources() {
if (!hasITuner()) {
ALOGE("Failed to updateTunerResources");
diff --git a/services/tuner/hidl/TunerHidlService.h b/services/tuner/hidl/TunerHidlService.h
index 2b8750e..2252d35 100644
--- a/services/tuner/hidl/TunerHidlService.h
+++ b/services/tuner/hidl/TunerHidlService.h
@@ -24,13 +24,17 @@
#include <android/hardware/tv/tuner/1.1/ITuner.h>
#include <utils/Mutex.h>
+#include <unordered_set>
+
#include "TunerHelper.h"
#include "TunerHidlFilter.h"
+#include "TunerHidlFrontend.h"
using ::aidl::android::hardware::tv::tuner::DemuxCapabilities;
using ::aidl::android::hardware::tv::tuner::DemuxFilterEvent;
using ::aidl::android::hardware::tv::tuner::DemuxFilterStatus;
using ::aidl::android::hardware::tv::tuner::FrontendInfo;
+using ::aidl::android::hardware::tv::tuner::FrontendType;
using ::aidl::android::media::tv::tuner::ITunerDemux;
using ::aidl::android::media::tv::tuner::ITunerDescrambler;
using ::aidl::android::media::tv::tuner::ITunerFrontend;
@@ -85,9 +89,15 @@
::ndk::ScopedAStatus openSharedFilter(const string& in_filterToken,
const shared_ptr<ITunerFilterCallback>& in_cb,
shared_ptr<ITunerFilter>* _aidl_return) override;
+ ::ndk::ScopedAStatus setLna(bool in_bEnable) override;
+ ::ndk::ScopedAStatus setMaxNumberOfFrontends(FrontendType in_frontendType,
+ int32_t in_maxNumber) override;
+ ::ndk::ScopedAStatus getMaxNumberOfFrontends(FrontendType in_frontendType,
+ int32_t* _aidl_return) override;
string addFilterToShared(const shared_ptr<TunerHidlFilter>& sharedFilter);
void removeSharedFilter(const shared_ptr<TunerHidlFilter>& sharedFilter);
+ void removeFrontend(const shared_ptr<TunerHidlFrontend>& frontend);
static shared_ptr<TunerHidlService> getTunerService();
@@ -108,6 +118,9 @@
int mTunerVersion = TUNER_HAL_VERSION_UNKNOWN;
Mutex mSharedFiltersLock;
map<string, shared_ptr<TunerHidlFilter>> mSharedFilters;
+ Mutex mOpenedFrontendsLock;
+ unordered_set<shared_ptr<TunerHidlFrontend>> mOpenedFrontends;
+ int mLnaStatus = -1;
static shared_ptr<TunerHidlService> sTunerService;
};