Merge "Camera: Enable the rotate&crop heuristics in the legacy shim layer" into tm-dev
diff --git a/apex/manifest.json b/apex/manifest.json
index 752c2b5..f908f97 100644
--- a/apex/manifest.json
+++ b/apex/manifest.json
@@ -1,6 +1,6 @@
{
"name": "com.android.media",
- "version": 330100000,
+ "version": 330090000,
"requireNativeLibs": [
"libandroid.so",
"libbinder_ndk.so",
diff --git a/apex/manifest_codec.json b/apex/manifest_codec.json
index 3732a76..01a85ae 100644
--- a/apex/manifest_codec.json
+++ b/apex/manifest_codec.json
@@ -1,6 +1,6 @@
{
"name": "com.android.media.swcodec",
- "version": 330100000,
+ "version": 330090000,
"requireNativeLibs": [
":sphal"
]
diff --git a/camera/aidl/android/hardware/ICameraServiceProxy.aidl b/camera/aidl/android/hardware/ICameraServiceProxy.aidl
index f5d0120..88783fb 100644
--- a/camera/aidl/android/hardware/ICameraServiceProxy.aidl
+++ b/camera/aidl/android/hardware/ICameraServiceProxy.aidl
@@ -44,4 +44,9 @@
* {@link android.hardware.camera2.CameraMetadata#SCALER_ROTATE_AND_CROP_270}).
*/
int getRotateAndCropOverride(String packageName, int lensFacing, int userId);
+
+ /**
+ * Checks if the camera has been disabled via device policy.
+ */
+ boolean isCameraDisabled();
}
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 3f7ff8b..913854c 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -858,7 +858,7 @@
* routine is enabled, overriding the application's selected
* ACAMERA_COLOR_CORRECTION_TRANSFORM, ACAMERA_COLOR_CORRECTION_GAINS and
* ACAMERA_COLOR_CORRECTION_MODE. Note that when ACAMERA_CONTROL_AE_MODE
- * is OFF, the behavior of AWB is device dependent. It is recommened to
+ * is OFF, the behavior of AWB is device dependent. It is recommended to
* also set AWB mode to OFF or lock AWB by using ACAMERA_CONTROL_AWB_LOCK before
* setting AE mode to OFF.</p>
* <p>When set to the OFF mode, the camera device's auto-white balance
@@ -989,13 +989,15 @@
*
* <p>This control (except for MANUAL) is only effective if
* <code>ACAMERA_CONTROL_MODE != OFF</code> and any 3A routine is active.</p>
- * <p>All intents are supported by all devices, except that:
- * * ZERO_SHUTTER_LAG will be supported if ACAMERA_REQUEST_AVAILABLE_CAPABILITIES contains
- * PRIVATE_REPROCESSING or YUV_REPROCESSING.
- * * MANUAL will be supported if ACAMERA_REQUEST_AVAILABLE_CAPABILITIES contains
- * MANUAL_SENSOR.
- * * MOTION_TRACKING will be supported if ACAMERA_REQUEST_AVAILABLE_CAPABILITIES contains
- * MOTION_TRACKING.</p>
+ * <p>All intents are supported by all devices, except that:</p>
+ * <ul>
+ * <li>ZERO_SHUTTER_LAG will be supported if ACAMERA_REQUEST_AVAILABLE_CAPABILITIES contains
+ * PRIVATE_REPROCESSING or YUV_REPROCESSING.</li>
+ * <li>MANUAL will be supported if ACAMERA_REQUEST_AVAILABLE_CAPABILITIES contains
+ * MANUAL_SENSOR.</li>
+ * <li>MOTION_TRACKING will be supported if ACAMERA_REQUEST_AVAILABLE_CAPABILITIES contains
+ * MOTION_TRACKING.</li>
+ * </ul>
*
* @see ACAMERA_CONTROL_MODE
* @see ACAMERA_REQUEST_AVAILABLE_CAPABILITIES
@@ -1486,7 +1488,7 @@
* Any state (excluding LOCKED) | ACAMERA_CONTROL_AE_PRECAPTURE_TRIGGER is START, sequence done | FLASH_REQUIRED | Converged but too dark w/o flash after a precapture sequence, transient states are skipped by camera device.
* Any state (excluding LOCKED) | ACAMERA_CONTROL_AE_PRECAPTURE_TRIGGER is START, sequence done | CONVERGED | Converged after a precapture sequence, transient states are skipped by camera device.
* Any state (excluding LOCKED) | ACAMERA_CONTROL_AE_PRECAPTURE_TRIGGER is CANCEL, converged | FLASH_REQUIRED | Converged but too dark w/o flash after a precapture sequence is canceled, transient states are skipped by camera device.
- * Any state (excluding LOCKED) | ACAMERA_CONTROL_AE_PRECAPTURE_TRIGGER is CANCEL, converged | CONVERGED | Converged after a precapture sequenceis canceled, transient states are skipped by camera device.
+ * Any state (excluding LOCKED) | ACAMERA_CONTROL_AE_PRECAPTURE_TRIGGER is CANCEL, converged | CONVERGED | Converged after a precapture sequences canceled, transient states are skipped by camera device.
* CONVERGED | Camera device finished AE scan | FLASH_REQUIRED | Converged but too dark w/o flash after a new scan, transient states are skipped by camera device.
* FLASH_REQUIRED | Camera device finished AE scan | CONVERGED | Converged after a new scan, transient states are skipped by camera device.</p>
*
@@ -1722,7 +1724,7 @@
* </ul></p>
*
* <p>Devices support post RAW sensitivity boost will advertise
- * ACAMERA_CONTROL_POST_RAW_SENSITIVITY_BOOST key for controling
+ * ACAMERA_CONTROL_POST_RAW_SENSITIVITY_BOOST key for controlling
* post RAW sensitivity boost.</p>
* <p>This key will be <code>null</code> for devices that do not support any RAW format
* outputs. For devices that do support RAW format outputs, this key will always
@@ -2193,7 +2195,7 @@
*
* <p>If this value is greater than 1, then the device supports controlling the
* flashlight brightness level via
- * {android.hardware.camera2.CameraManager#turnOnTorchWithStrengthLevel}.
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraManager.html#turnOnTorchWithStrengthLevel">CameraManager#turnOnTorchWithStrengthLevel</a>.
* If this value is equal to 1, flashlight brightness control is not supported.
* The value for this key will be null for devices with no flash unit.</p>
*/
@@ -2201,7 +2203,7 @@
ACAMERA_FLASH_INFO_START + 2,
/**
* <p>Default flashlight brightness level to be set via
- * {android.hardware.camera2.CameraManager#turnOnTorchWithStrengthLevel}.</p>
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraManager.html#turnOnTorchWithStrengthLevel">CameraManager#turnOnTorchWithStrengthLevel</a>.</p>
*
* <p>Type: int32</p>
*
@@ -2423,7 +2425,7 @@
* and keep jpeg and thumbnail image data unrotated.</li>
* <li>Rotate the jpeg and thumbnail image data and not set
* <a href="https://developer.android.com/reference/android/media/ExifInterface.html#TAG_ORIENTATION">EXIF orientation flag</a>. In this
- * case, LIMITED or FULL hardware level devices will report rotated thumnail size in
+ * case, LIMITED or FULL hardware level devices will report rotated thumbnail size in
* capture result, so the width and height will be interchanged if 90 or 270 degree
* orientation is requested. LEGACY device will always report unrotated thumbnail
* size.</li>
@@ -2452,7 +2454,7 @@
*
* <p>This list will include at least one non-zero resolution, plus <code>(0,0)</code> for indicating no
* thumbnail should be generated.</p>
- * <p>Below condiditions will be satisfied for this size list:</p>
+ * <p>Below conditions will be satisfied for this size list:</p>
* <ul>
* <li>The sizes will be sorted by increasing pixel area (width x height).
* If several resolutions have the same area, they will be sorted by increasing width.</li>
@@ -2766,7 +2768,7 @@
* <p>When the state is STATIONARY, the lens parameters are not changing. This could be
* either because the parameters are all fixed, or because the lens has had enough
* time to reach the most recently-requested values.
- * If all these lens parameters are not changable for a camera device, as listed below:</p>
+ * If all these lens parameters are not changeable for a camera device, as listed below:</p>
* <ul>
* <li>Fixed focus (<code>ACAMERA_LENS_INFO_MINIMUM_FOCUS_DISTANCE == 0</code>), which means
* ACAMERA_LENS_FOCUS_DISTANCE parameter will always be 0.</li>
@@ -3218,7 +3220,7 @@
* the camera device. Using more streams simultaneously may require more hardware and
* CPU resources that will consume more power. The image format for an output stream can
* be any supported format provided by ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS.
- * The formats defined in ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS can be catergorized
+ * The formats defined in ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS can be categorized
* into the 3 stream types as below:</p>
* <ul>
* <li>Processed (but stalling): any non-RAW format with a stallDurations > 0.
@@ -3445,7 +3447,7 @@
* but clients should be aware and expect delays during their application.
* An example usage scenario could look like this:</p>
* <ul>
- * <li>The camera client starts by quering the session parameter key list via
+ * <li>The camera client starts by querying the session parameter key list via
* {@link ACameraManager_getCameraCharacteristics }.</li>
* <li>Before triggering the capture session create sequence, a capture request
* must be built via
@@ -3711,7 +3713,7 @@
* 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
* 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,
+ * <a href="https://developer.android.com/reference/android/os/Build/VERSION_CODES/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
@@ -3730,7 +3732,7 @@
* 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 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,
+ * <a href="https://developer.android.com/reference/android/os/Build/VERSION_CODES/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>
@@ -4224,14 +4226,16 @@
* to output different resolution images depending on the current active physical camera or
* pixel mode. With multi-resolution input streams, the camera device can reprocess images
* of different resolutions from different physical cameras or sensor pixel modes.</p>
- * <p>When set to TRUE:
- * * For a logical multi-camera, the camera framework derives
+ * <p>When set to TRUE:</p>
+ * <ul>
+ * <li>For a logical multi-camera, the camera framework derives
* android.scaler.multiResolutionStreamConfigurationMap by combining the
* ACAMERA_SCALER_PHYSICAL_CAMERA_MULTI_RESOLUTION_STREAM_CONFIGURATIONS from its physical
- * cameras.
- * * For an ultra-high resolution sensor camera, the camera framework directly copies
+ * cameras.</li>
+ * <li>For an ultra-high resolution sensor camera, the camera framework directly copies
* the value of ACAMERA_SCALER_PHYSICAL_CAMERA_MULTI_RESOLUTION_STREAM_CONFIGURATIONS to
- * android.scaler.multiResolutionStreamConfigurationMap.</p>
+ * android.scaler.multiResolutionStreamConfigurationMap.</li>
+ * </ul>
*
* @see ACAMERA_SCALER_PHYSICAL_CAMERA_MULTI_RESOLUTION_STREAM_CONFIGURATIONS
*/
@@ -4253,7 +4257,7 @@
* capture, video record for encoding the camera output for the purpose of future playback,
* and video call for live realtime video conferencing.</p>
* <p>With this flag, the camera device can optimize the image processing pipeline
- * parameters, such as tuning, sensor mode, and ISP settings, indepedent of
+ * parameters, such as tuning, sensor mode, and ISP settings, independent of
* the properties of the immediate camera output surface. For example, if the output
* surface is a SurfaceTexture, the stream use case flag can be used to indicate whether
* the camera frames eventually go to display, video encoder,
@@ -4275,7 +4279,7 @@
* <a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE">CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE</a>
* capability is documented in the camera device
* <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession">guideline</a>. The
- * application is strongly recommended to use one of the guaranteed stream combintations.
+ * application is strongly recommended to use one of the guaranteed stream combinations.
* If the application creates a session with a stream combination not in the guaranteed
* list, or with mixed DEFAULT and non-DEFAULT use cases within the same session,
* the camera device may ignore some stream use cases due to hardware constraints
@@ -4839,7 +4843,7 @@
* noise model used here is:</p>
* <p>N(x) = sqrt(Sx + O)</p>
* <p>Where x represents the recorded signal of a CFA channel normalized to
- * the range [0, 1], and S and O are the noise model coeffiecients for
+ * the range [0, 1], and S and O are the noise model coefficients for
* that channel.</p>
* <p>A more detailed description of the noise model can be found in the
* Adobe DNG specification for the NoiseProfile tag.</p>
@@ -4888,7 +4892,7 @@
* <li>1.20 <= R >= 1.03 will require some software
* correction to avoid demosaic errors (3-20% divergence).</li>
* <li>R > 1.20 will require strong software correction to produce
- * a usuable image (>20% divergence).</li>
+ * a usable image (>20% divergence).</li>
* </ul>
* <p>Starting from Android Q, this key will not be present for a MONOCHROME camera, even if
* the camera device has RAW capability.</p>
@@ -5145,7 +5149,7 @@
* <li>ACameraMetadata from ACameraCaptureSession_captureCallback_result callbacks</li>
* </ul></p>
*
- * <p>This key will only be present in devices advertisting the
+ * <p>This key will only be present in devices advertising the
* <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR">CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR</a>
* capability which also advertise <code>REMOSAIC_REPROCESSING</code> capability. On all other devices
* RAW targets will have a regular bayer pattern.</p>
@@ -6330,9 +6334,11 @@
* <li>ACaptureRequest</li>
* </ul></p>
*
- * <p>The tonemap curve will be defined the following formula:
- * * OUT = pow(IN, 1.0 / gamma)
- * where IN and OUT is the input pixel value scaled to range [0.0, 1.0],
+ * <p>The tonemap curve will be defined the following formula:</p>
+ * <ul>
+ * <li>OUT = pow(IN, 1.0 / gamma)</li>
+ * </ul>
+ * <p>where IN and OUT is the input pixel value scaled to range [0.0, 1.0],
* pow is the power function and gamma is the gamma value specified by this
* key.</p>
* <p>The same curve will be applied to all color channels. The camera device
@@ -7294,7 +7300,7 @@
* EXTERIOR_* value.</p>
* <p>If a camera has INTERIOR_OTHER or EXTERIOR_OTHER, or more than one camera is at the
* same location and facing the same direction, their static metadata will list the
- * following entries, so that applications can determain their lenses' exact facing
+ * following entries, so that applications can determine their lenses' exact facing
* directions:</p>
* <ul>
* <li>ACAMERA_LENS_POSE_REFERENCE</li>
@@ -8705,7 +8711,7 @@
/**
* <p>The value of ACAMERA_LENS_POSE_TRANSLATION is relative to the origin of the
- * automotive sensor coodinate system, which is at the center of the rear axle.</p>
+ * automotive sensor coordinate system, which is at the center of the rear axle.</p>
*
* @see ACAMERA_LENS_POSE_TRANSLATION
*/
@@ -9024,7 +9030,7 @@
* for the largest YUV_420_888 size.</p>
* <p>If the device supports the {@link AIMAGE_FORMAT_RAW10 }, {@link AIMAGE_FORMAT_RAW12 }, {@link AIMAGE_FORMAT_Y8 }, then those can also be
* captured at the same rate as the maximum-size YUV_420_888 resolution is.</p>
- * <p>In addition, the ACAMERA_SYNC_MAX_LATENCY field is guaranted to have a value between 0
+ * <p>In addition, the ACAMERA_SYNC_MAX_LATENCY field is guaranteed to have a value between 0
* and 4, inclusive. ACAMERA_CONTROL_AE_LOCK_AVAILABLE and ACAMERA_CONTROL_AWB_LOCK_AVAILABLE
* are also guaranteed to be <code>true</code> so burst capture with these two locks ON yields
* consistent image output.</p>
@@ -9190,7 +9196,7 @@
* non-active physical cameras. For example, if the logical camera has a wide-ultrawide
* configuration where the wide lens is the default, when the crop region is set to the
* logical camera's active array size, (and the zoom ratio set to 1.0 starting from
- * Android 11), a physical stream for the ultrawide camera may prefer outputing images
+ * Android 11), a physical stream for the ultrawide camera may prefer outputting images
* with larger field-of-view than that of the wide camera for better stereo matching
* margin or more robust motion tracking. At the same time, the physical non-RAW streams'
* field of view must not be smaller than the requested crop region and zoom ratio, as
@@ -9316,22 +9322,26 @@
* <a href="https://developer.android.com/reference/android/hardware/camera2/params/OutputConfiguration.html#setStreamUseCase">OutputConfiguration#setStreamUseCase</a>
* so that the device can optimize camera pipeline parameters such as tuning, sensor
* mode, or ISP settings for a specific user scenario.
- * Some sample usages of this capability are:
- * * Distinguish high quality YUV captures from a regular YUV stream where
- * the image quality may not be as good as the JPEG stream, or
- * * Use one stream to serve multiple purposes: viewfinder, video recording and
+ * Some sample usages of this capability are:</p>
+ * <ul>
+ * <li>Distinguish high quality YUV captures from a regular YUV stream where
+ * the image quality may not be as good as the JPEG stream, or</li>
+ * <li>Use one stream to serve multiple purposes: viewfinder, video recording and
* still capture. This is common with applications that wish to apply edits equally
- * to preview, saved images, and saved videos.</p>
+ * to preview, saved images, and saved videos.</li>
+ * </ul>
* <p>This capability requires the camera device to support the following
- * stream use cases:
- * * DEFAULT for backward compatibility where the application doesn't set
- * a stream use case
- * * PREVIEW for live viewfinder and in-app image analysis
- * * STILL_CAPTURE for still photo capture
- * * VIDEO_RECORD for recording video clips
- * * PREVIEW_VIDEO_STILL for one single stream used for viewfinder, video
- * recording, and still capture.
- * * VIDEO_CALL for long running video calls</p>
+ * stream use cases:</p>
+ * <ul>
+ * <li>DEFAULT for backward compatibility where the application doesn't set
+ * a stream use case</li>
+ * <li>PREVIEW for live viewfinder and in-app image analysis</li>
+ * <li>STILL_CAPTURE for still photo capture</li>
+ * <li>VIDEO_RECORD for recording video clips</li>
+ * <li>PREVIEW_VIDEO_STILL for one single stream used for viewfinder, video
+ * recording, and still capture.</li>
+ * <li>VIDEO_CALL for long running video calls</li>
+ * </ul>
* <p><a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#SCALER_AVAILABLE_STREAM_USE_CASES">CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES</a>
* lists all of the supported stream use cases.</p>
* <p>Refer to <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession">CameraDevice#createCaptureSession</a> for the
@@ -9632,10 +9642,10 @@
* <p>Live stream shown to the user.</p>
* <p>Optimized for performance and usability as a viewfinder, but not necessarily for
* image quality. The output is not meant to be persisted as saved images or video.</p>
- * <p>No stall if android.control.<em> are set to FAST; may have stall if android.control.</em>
- * are set to HIGH_QUALITY. This use case has the same behavior as the default
- * SurfaceView and SurfaceTexture targets. Additionally, this use case can be used for
- * in-app image analysis.</p>
+ * <p>No stall if ACAMERA_CONTROL_* are set to FAST. There may be stall if
+ * they are set to HIGH_QUALITY. This use case has the same behavior as the
+ * default SurfaceView and SurfaceTexture targets. Additionally, this use case can be
+ * used for in-app image analysis.</p>
*/
ACAMERA_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW = 0x1,
@@ -9678,7 +9688,7 @@
ACAMERA_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL = 0x4,
/**
- * <p>Long-running video call optimized for both power efficienty and video quality.</p>
+ * <p>Long-running video call optimized for both power efficiency and video quality.</p>
* <p>The camera sensor may run in a lower-resolution mode to reduce power consumption
* at the cost of some image and digital zoom quality. Unlike VIDEO_RECORD, VIDEO_CALL
* outputs are expected to work in dark conditions, so are usually accompanied with
@@ -10105,7 +10115,7 @@
ACAMERA_TONEMAP_MODE_HIGH_QUALITY = 2,
/**
- * <p>Use the gamma value specified in ACAMERA_TONEMAP_GAMMA to peform
+ * <p>Use the gamma value specified in ACAMERA_TONEMAP_GAMMA to perform
* tonemapping.</p>
* <p>All color enhancement and tonemapping must be disabled, except
* for applying the tonemapping curve specified by ACAMERA_TONEMAP_GAMMA.</p>
@@ -10117,7 +10127,7 @@
/**
* <p>Use the preset tonemapping curve specified in
- * ACAMERA_TONEMAP_PRESET_CURVE to peform tonemapping.</p>
+ * ACAMERA_TONEMAP_PRESET_CURVE to perform tonemapping.</p>
* <p>All color enhancement and tonemapping must be disabled, except
* for applying the tonemapping curve specified by
* ACAMERA_TONEMAP_PRESET_CURVE.</p>
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
index 85ab0c2..0a57590 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
@@ -491,6 +491,7 @@
}
if (mRemote != nullptr) {
+ ALOGD("%s: binder disconnect reached", __FUNCTION__);
auto ret = mRemote->disconnect();
if (!ret.isOk()) {
ALOGE("%s: Transaction error while disconnecting device %s", __FUNCTION__,
diff --git a/drm/drmserver/DrmManager.cpp b/drm/drmserver/DrmManager.cpp
index 74e3223..f7989bd 100644
--- a/drm/drmserver/DrmManager.cpp
+++ b/drm/drmserver/DrmManager.cpp
@@ -208,7 +208,11 @@
}
status_t DrmManager::loadPlugIns() {
+#if __LP64__
+ String8 pluginDirPath("/system/lib64/drm");
+#else
String8 pluginDirPath("/system/lib/drm");
+#endif
loadPlugIns(pluginDirPath);
return DRM_NO_ERROR;
}
diff --git a/drm/mediadrm/plugins/clearkey/hidl/Android.bp b/drm/mediadrm/plugins/clearkey/hidl/Android.bp
index 02ac943..b82d996 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/Android.bp
+++ b/drm/mediadrm/plugins/clearkey/hidl/Android.bp
@@ -144,7 +144,6 @@
"libclearkeydevicefiles-protos",
"libjsmn",
"libprotobuf-cpp-lite",
- "libutils",
],
shared_libs: [
"android.hidl.allocator@1.0",
@@ -157,6 +156,7 @@
"libhidlbase",
"libhidlmemory",
"liblog",
+ "libutils",
],
fuzz_config: {
cc: [
diff --git a/drm/mediadrm/plugins/clearkey/service-lazy.mk b/drm/mediadrm/plugins/clearkey/service-lazy.mk
new file mode 100644
index 0000000..0d16f4c
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/service-lazy.mk
@@ -0,0 +1,16 @@
+#
+# 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.
+#
+PRODUCT_PACKAGES += android.hardware.drm-service-lazy.clearkey
diff --git a/drm/mediadrm/plugins/clearkey/service.mk b/drm/mediadrm/plugins/clearkey/service.mk
new file mode 100644
index 0000000..15988fb
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/service.mk
@@ -0,0 +1,16 @@
+#
+# 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.
+#
+PRODUCT_PACKAGES += android.hardware.drm-service.clearkey
diff --git a/media/codec2/components/aom/C2SoftAomDec.cpp b/media/codec2/components/aom/C2SoftAomDec.cpp
index c7985ca..3b0e949 100644
--- a/media/codec2/components/aom/C2SoftAomDec.cpp
+++ b/media/codec2/components/aom/C2SoftAomDec.cpp
@@ -261,8 +261,7 @@
CREATE_DUMP_FILE(mInFile);
CREATE_DUMP_FILE(mOutFile);
- gettimeofday(&mTimeStart, nullptr);
- gettimeofday(&mTimeEnd, nullptr);
+ mTimeStart = mTimeEnd = systemTime();
}
C2SoftAomDec::~C2SoftAomDec() {
@@ -463,19 +462,17 @@
int64_t frameIndex = work->input.ordinal.frameIndex.peekll();
if (inSize) {
uint8_t* bitstream = const_cast<uint8_t*>(rView.data() + inOffset);
- int32_t decodeTime = 0;
- int32_t delay = 0;
DUMP_TO_FILE(mOutFile, bitstream, inSize);
- GETTIME(&mTimeStart, nullptr);
- TIME_DIFF(mTimeEnd, mTimeStart, delay);
+ mTimeStart = systemTime();
+ nsecs_t delay = mTimeStart - mTimeEnd;
aom_codec_err_t err =
aom_codec_decode(mCodecCtx, bitstream, inSize, &frameIndex);
- GETTIME(&mTimeEnd, nullptr);
- TIME_DIFF(mTimeStart, mTimeEnd, decodeTime);
- ALOGV("decodeTime=%4d delay=%4d\n", decodeTime, delay);
+ mTimeEnd = systemTime();
+ nsecs_t decodeTime = mTimeEnd - mTimeStart;
+ ALOGV("decodeTime=%4" PRId64 " delay=%4" PRId64 "\n", decodeTime, delay);
if (err != AOM_CODEC_OK) {
ALOGE("av1 decoder failed to decode frame err: %d", err);
diff --git a/media/codec2/components/aom/C2SoftAomDec.h b/media/codec2/components/aom/C2SoftAomDec.h
index 4c82647..8b953fe 100644
--- a/media/codec2/components/aom/C2SoftAomDec.h
+++ b/media/codec2/components/aom/C2SoftAomDec.h
@@ -17,15 +17,12 @@
#ifndef ANDROID_C2_SOFT_AV1_DEC_H_
#define ANDROID_C2_SOFT_AV1_DEC_H_
+#include <inttypes.h>
+
#include <SimpleC2Component.h>
#include "aom/aom_decoder.h"
#include "aom/aomdx.h"
-#define GETTIME(a, b) gettimeofday(a, b);
-#define TIME_DIFF(start, end, diff) \
- diff = (((end).tv_sec - (start).tv_sec) * 1000000) + \
- ((end).tv_usec - (start).tv_usec);
-
namespace android {
struct C2SoftAomDec : public SimpleC2Component {
@@ -60,8 +57,8 @@
char mOutFile[200];
#endif /* FILE_DUMP_ENABLE */
- struct timeval mTimeStart; // Time at the start of decode()
- struct timeval mTimeEnd; // Time at the end of decode()
+ nsecs_t mTimeStart = 0; // Time at the start of decode()
+ nsecs_t mTimeEnd = 0; // Time at the end of decode()
status_t initDecoder();
status_t destroyDecoder();
@@ -85,14 +82,13 @@
#define OUTPUT_DUMP_EXT "av1"
#define GENERATE_FILE_NAMES() \
{ \
- GETTIME(&mTimeStart, NULL); \
- strcpy(mInFile, ""); \
+ nsecs_t now = systemTime(); \
ALOGD("GENERATE_FILE_NAMES"); \
- sprintf(mInFile, "%s_%ld.%ld.%s", INPUT_DUMP_PATH, mTimeStart.tv_sec, \
- mTimeStart.tv_usec, INPUT_DUMP_EXT); \
+ sprintf(mInFile, "%s_%" PRId64 ".%s", INPUT_DUMP_PATH, \
+ now, INPUT_DUMP_EXT); \
strcpy(mOutFile, ""); \
- sprintf(mOutFile, "%s_%ld.%ld.%s", OUTPUT_DUMP_PATH, \
- mTimeStart.tv_sec, mTimeStart.tv_usec, OUTPUT_DUMP_EXT); \
+ sprintf(mOutFile, "%s_%" PRId64 ".%s", OUTPUT_DUMP_PATH, \
+ now, OUTPUT_DUMP_EXT); \
}
#define CREATE_DUMP_FILE(m_filename) \
diff --git a/media/codec2/components/avc/C2SoftAvcDec.cpp b/media/codec2/components/avc/C2SoftAvcDec.cpp
index cc4517d..953afc5 100644
--- a/media/codec2/components/avc/C2SoftAvcDec.cpp
+++ b/media/codec2/components/avc/C2SoftAvcDec.cpp
@@ -670,8 +670,7 @@
void C2SoftAvcDec::resetPlugin() {
mSignalledOutputEos = false;
- gettimeofday(&mTimeStart, nullptr);
- gettimeofday(&mTimeEnd, nullptr);
+ mTimeStart = mTimeEnd = systemTime();
}
status_t C2SoftAvcDec::deleteDecoder() {
@@ -866,14 +865,13 @@
setParams(mStride, IVD_DECODE_HEADER);
}
- WORD32 delay;
- GETTIME(&mTimeStart, nullptr);
- TIME_DIFF(mTimeEnd, mTimeStart, delay);
+ mTimeStart = systemTime();
+ nsecs_t delay = mTimeStart - mTimeEnd;
(void) ivdec_api_function(mDecHandle, &s_h264d_decode_ip, &s_h264d_decode_op);
- WORD32 decodeTime;
- GETTIME(&mTimeEnd, nullptr);
- TIME_DIFF(mTimeStart, mTimeEnd, decodeTime);
- ALOGV("decodeTime=%6d delay=%6d numBytes=%6d", decodeTime, delay,
+
+ mTimeEnd = systemTime();
+ nsecs_t decodeTime = mTimeEnd - mTimeStart;
+ ALOGV("decodeTime=%" PRId64 " delay=%" PRId64 " numBytes=%6d", decodeTime, delay,
ps_decode_op->u4_num_bytes_consumed);
}
if (IVD_MEM_ALLOC_FAILED == (ps_decode_op->u4_error_code & IVD_ERROR_MASK)) {
diff --git a/media/codec2/components/avc/C2SoftAvcDec.h b/media/codec2/components/avc/C2SoftAvcDec.h
index 59d5184..36a463e 100644
--- a/media/codec2/components/avc/C2SoftAvcDec.h
+++ b/media/codec2/components/avc/C2SoftAvcDec.h
@@ -18,6 +18,7 @@
#define ANDROID_C2_SOFT_AVC_DEC_H_
#include <sys/time.h>
+#include <inttypes.h>
#include <media/stagefright/foundation/ColorUtils.h>
@@ -43,19 +44,15 @@
#define IVDEXT_CMD_CTL_SET_NUM_CORES \
(IVD_CONTROL_API_COMMAND_TYPE_T)IH264D_CMD_CTL_SET_NUM_CORES
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
-#define GETTIME(a, b) gettimeofday(a, b);
-#define TIME_DIFF(start, end, diff) \
- diff = (((end).tv_sec - (start).tv_sec) * 1000000) + \
- ((end).tv_usec - (start).tv_usec);
#ifdef FILE_DUMP_ENABLE
#define INPUT_DUMP_PATH "/sdcard/clips/avcd_input"
#define INPUT_DUMP_EXT "h264"
#define GENERATE_FILE_NAMES() { \
- GETTIME(&mTimeStart, NULL); \
+ nsecs_t now = systemTime(); \
strcpy(mInFile, ""); \
- sprintf(mInFile, "%s_%ld.%ld.%s", INPUT_DUMP_PATH, \
- mTimeStart.tv_sec, mTimeStart.tv_usec, \
+ sprintf(mInFile, "%s_%" PRId64 "d.%s", \
+ INPUT_DUMP_PATH, now, \
INPUT_DUMP_EXT); \
}
#define CREATE_DUMP_FILE(m_filename) { \
@@ -183,8 +180,8 @@
} mBitstreamColorAspects;
// profile
- struct timeval mTimeStart;
- struct timeval mTimeEnd;
+ nsecs_t mTimeStart = 0;
+ nsecs_t mTimeEnd = 0;
#ifdef FILE_DUMP_ENABLE
char mInFile[200];
#endif /* FILE_DUMP_ENABLE */
diff --git a/media/codec2/components/avc/C2SoftAvcEnc.cpp b/media/codec2/components/avc/C2SoftAvcEnc.cpp
index d65ffa5..4ffcd59 100644
--- a/media/codec2/components/avc/C2SoftAvcEnc.cpp
+++ b/media/codec2/components/avc/C2SoftAvcEnc.cpp
@@ -656,8 +656,7 @@
mEntropyMode = DEFAULT_ENTROPY_MODE;
mBframes = DEFAULT_B_FRAMES;
- gettimeofday(&mTimeStart, nullptr);
- gettimeofday(&mTimeEnd, nullptr);
+ mTimeStart = mTimeEnd = systemTime();
}
c2_status_t C2SoftAvcEnc::setDimensions() {
@@ -1650,8 +1649,7 @@
work->worklets.front()->output.flags = work->input.flags;
IV_STATUS_T status;
- WORD32 timeDelay = 0;
- WORD32 timeTaken = 0;
+ nsecs_t timeDelay = 0;
uint64_t workIndex = work->input.ordinal.frameIndex.peekull();
// Initialize encoder if not already initialized
@@ -1817,10 +1815,10 @@
// mInFile, s_encode_ip.s_inp_buf.apv_bufs[0],
// (mHeight * mStride * 3 / 2));
- GETTIME(&mTimeStart, nullptr);
/* Compute time elapsed between end of previous decode()
* to start of current decode() */
- TIME_DIFF(mTimeEnd, mTimeStart, timeDelay);
+ mTimeStart = systemTime();
+ timeDelay = mTimeStart - mTimeEnd;
status = ive_api_function(mCodecCtx, &s_video_encode_ip, &s_video_encode_op);
if (IV_SUCCESS != status) {
@@ -1844,11 +1842,11 @@
mBuffers[ps_encode_ip->s_inp_buf.apv_bufs[0]] = inputBuffer;
}
- GETTIME(&mTimeEnd, nullptr);
/* Compute time taken for decode() */
- TIME_DIFF(mTimeStart, mTimeEnd, timeTaken);
+ mTimeEnd = systemTime();
+ nsecs_t timeTaken = mTimeEnd - mTimeStart;
- ALOGV("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay,
+ ALOGV("timeTaken=%" PRId64 "d delay=%" PRId64 " numBytes=%6d", timeTaken, timeDelay,
ps_encode_op->s_out_buf.u4_bytes);
void *freed = ps_encode_op->s_inp_buf.apv_bufs[0];
diff --git a/media/codec2/components/avc/C2SoftAvcEnc.h b/media/codec2/components/avc/C2SoftAvcEnc.h
index 1fecd9e..293867d 100644
--- a/media/codec2/components/avc/C2SoftAvcEnc.h
+++ b/media/codec2/components/avc/C2SoftAvcEnc.h
@@ -18,6 +18,7 @@
#define ANDROID_C2_SOFT_AVC_ENC_H__
#include <map>
+#include <inttypes.h>
#include <utils/Vector.h>
@@ -115,14 +116,6 @@
/** Used to remove warnings about unused parameters */
#define UNUSED(x) ((void)(x))
-/** Get time */
-#define GETTIME(a, b) gettimeofday(a, b);
-
-/** Compute difference between start and end */
-#define TIME_DIFF(start, end, diff) \
- diff = (((end).tv_sec - (start).tv_sec) * 1000000) + \
- ((end).tv_usec - (start).tv_usec);
-
#define ive_aligned_malloc(alignment, size) memalign(alignment, size)
#define ive_aligned_free(buf) free(buf)
@@ -148,6 +141,7 @@
virtual ~C2SoftAvcEnc();
private:
+ // RBE What does OMX have to do with the c2 plugin?
// OMX input buffer's timestamp and flags
typedef struct {
int64_t mTimeUs;
@@ -158,8 +152,8 @@
int32_t mStride;
- struct timeval mTimeStart; // Time at the start of decode()
- struct timeval mTimeEnd; // Time at the end of decode()
+ nsecs_t mTimeStart = 0; // Time at the start of decode()
+ nsecs_t mTimeEnd = 0; // Time at the end of decode()
#ifdef FILE_DUMP_ENABLE
char mInFile[200];
@@ -259,14 +253,14 @@
#define OUTPUT_DUMP_EXT "h264"
#define GENERATE_FILE_NAMES() { \
- GETTIME(&mTimeStart, NULL); \
+ nsecs_t now = systemTime(); \
strcpy(mInFile, ""); \
- sprintf(mInFile, "%s_%ld.%ld.%s", INPUT_DUMP_PATH, \
- mTimeStart.tv_sec, mTimeStart.tv_usec, \
+ sprintf(mInFile, "%s_%" PRId64 "d.%s", \
+ INPUT_DUMP_PATH, now, \
INPUT_DUMP_EXT); \
strcpy(mOutFile, ""); \
- sprintf(mOutFile, "%s_%ld.%ld.%s", OUTPUT_DUMP_PATH,\
- mTimeStart.tv_sec, mTimeStart.tv_usec, \
+ sprintf(mOutFile, "%s_%" PRId64 "d.%s", \
+ OUTPUT_DUMP_PATH, now, \
OUTPUT_DUMP_EXT); \
}
diff --git a/media/codec2/components/base/SimpleC2Component.cpp b/media/codec2/components/base/SimpleC2Component.cpp
index 5295822..b30eed5 100644
--- a/media/codec2/components/base/SimpleC2Component.cpp
+++ b/media/codec2/components/base/SimpleC2Component.cpp
@@ -32,6 +32,13 @@
constexpr uint8_t kNeutralUVBitDepth8 = 128;
constexpr uint16_t kNeutralUVBitDepth10 = 512;
+bool isAtLeastT() {
+ char deviceCodeName[PROP_VALUE_MAX];
+ __system_property_get("ro.build.version.codename", deviceCodeName);
+ return android_get_device_api_level() >= __ANDROID_API_T__ ||
+ !strcmp(deviceCodeName, "Tiramisu");
+}
+
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,
@@ -767,9 +774,9 @@
// Save supported hal pixel formats for bit depth of 10, the first time this is called
if (!mBitDepth10HalPixelFormats.size()) {
std::vector<int> halPixelFormats;
- // TODO(b/178229371) Enable HAL_PIXEL_FORMAT_YCBCR_P010 once framework supports it
- // halPixelFormats.push_back(HAL_PIXEL_FORMAT_YCBCR_P010);
-
+ if (isAtLeastT()) {
+ halPixelFormats.push_back(HAL_PIXEL_FORMAT_YCBCR_P010);
+ }
// since allowRGBA1010102 can chance in each call, but mBitDepth10HalPixelFormats
// is populated only once, allowRGBA1010102 is not considered at this stage.
halPixelFormats.push_back(HAL_PIXEL_FORMAT_RGBA_1010102);
diff --git a/media/codec2/components/base/SimpleC2Interface.cpp b/media/codec2/components/base/SimpleC2Interface.cpp
index 29740d1..993e602 100644
--- a/media/codec2/components/base/SimpleC2Interface.cpp
+++ b/media/codec2/components/base/SimpleC2Interface.cpp
@@ -28,6 +28,14 @@
/* SimpleInterface */
+static C2R SubscribedParamIndicesSetter(
+ bool mayBlock, C2InterfaceHelper::C2P<C2SubscribedParamIndicesTuning> &me) {
+ (void)mayBlock;
+ (void)me;
+
+ return C2R::Ok();
+}
+
SimpleInterface<void>::BaseParams::BaseParams(
const std::shared_ptr<C2ReflectorHelper> &reflector,
C2String name,
@@ -186,7 +194,7 @@
.withDefault(C2SubscribedParamIndicesTuning::AllocShared(0u))
.withFields({ C2F(mSubscribedParamIndices, m.values[0]).any(),
C2F(mSubscribedParamIndices, m.values).any() })
- .withSetter(Setter<C2SubscribedParamIndicesTuning>::NonStrictValuesWithNoDeps)
+ .withSetter(SubscribedParamIndicesSetter)
.build());
/* TODO
diff --git a/media/codec2/components/base/include/SimpleC2Component.h b/media/codec2/components/base/include/SimpleC2Component.h
index d244f45..52ae3b8 100644
--- a/media/codec2/components/base/include/SimpleC2Component.h
+++ b/media/codec2/components/base/include/SimpleC2Component.h
@@ -27,7 +27,7 @@
#include <media/stagefright/foundation/Mutexed.h>
namespace android {
-
+bool isAtLeastT();
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,
diff --git a/media/codec2/components/base/include/SimpleC2Interface.h b/media/codec2/components/base/include/SimpleC2Interface.h
index 2051d3d..916f392 100644
--- a/media/codec2/components/base/include/SimpleC2Interface.h
+++ b/media/codec2/components/base/include/SimpleC2Interface.h
@@ -209,6 +209,7 @@
return me.F(me.v.value).validatePossible(me.v.value);
}
+ // TODO(b/230146771): fix crash
static C2R NonStrictValuesWithNoDeps(
bool mayBlock, C2InterfaceHelper::C2P<type> &me) {
(void)mayBlock;
diff --git a/media/codec2/components/gav1/C2SoftGav1Dec.cpp b/media/codec2/components/gav1/C2SoftGav1Dec.cpp
index e5fbe99..f5c8138 100644
--- a/media/codec2/components/gav1/C2SoftGav1Dec.cpp
+++ b/media/codec2/components/gav1/C2SoftGav1Dec.cpp
@@ -190,11 +190,18 @@
.withSetter(ColorAspectsSetter, mDefaultColorAspects, mCodedColorAspects)
.build());
+ std::vector<uint32_t> pixelFormats = {HAL_PIXEL_FORMAT_YCBCR_420_888};
+ if (isAtLeastT()) {
+ pixelFormats.push_back(HAL_PIXEL_FORMAT_YCBCR_P010);
+ }
// TODO: support more formats?
- addParameter(DefineParam(mPixelFormat, C2_PARAMKEY_PIXEL_FORMAT)
- .withConstValue(new C2StreamPixelFormatInfo::output(
- 0u, HAL_PIXEL_FORMAT_YCBCR_420_888))
- .build());
+ addParameter(
+ DefineParam(mPixelFormat, C2_PARAMKEY_PIXEL_FORMAT)
+ .withDefault(new C2StreamPixelFormatInfo::output(
+ 0u, HAL_PIXEL_FORMAT_YCBCR_420_888))
+ .withFields({C2F(mPixelFormat, value).oneOf(pixelFormats)})
+ .withSetter((Setter<decltype(*mPixelFormat)>::StrictValueWithNoDeps))
+ .build());
}
static C2R SizeSetter(bool mayBlock,
@@ -335,8 +342,7 @@
std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
mIntf(intfImpl),
mCodecCtx(nullptr) {
- gettimeofday(&mTimeStart, nullptr);
- gettimeofday(&mTimeEnd, nullptr);
+ mTimeStart = mTimeEnd = systemTime();
}
C2SoftGav1Dec::~C2SoftGav1Dec() { onRelease(); }
@@ -403,6 +409,7 @@
bool C2SoftGav1Dec::initDecoder() {
mSignalledError = false;
mSignalledOutputEos = false;
+ mHalPixelFormat = HAL_PIXEL_FORMAT_YV12;
mCodecCtx.reset(new libgav1::Decoder());
if (mCodecCtx == nullptr) {
@@ -506,19 +513,17 @@
int64_t frameIndex = work->input.ordinal.frameIndex.peekll();
if (inSize) {
uint8_t *bitstream = const_cast<uint8_t *>(rView.data() + inOffset);
- int32_t decodeTime = 0;
- int32_t delay = 0;
- GETTIME(&mTimeStart, nullptr);
- TIME_DIFF(mTimeEnd, mTimeStart, delay);
+ mTimeStart = systemTime();
+ nsecs_t delay = mTimeStart - mTimeEnd;
const Libgav1StatusCode status =
mCodecCtx->EnqueueFrame(bitstream, inSize, frameIndex,
/*buffer_private_data=*/nullptr);
- GETTIME(&mTimeEnd, nullptr);
- TIME_DIFF(mTimeStart, mTimeEnd, decodeTime);
- ALOGV("decodeTime=%4d delay=%4d\n", decodeTime, delay);
+ mTimeEnd = systemTime();
+ nsecs_t decodeTime = mTimeEnd - mTimeStart;
+ ALOGV("decodeTime=%4" PRId64 " delay=%4" PRId64 "\n", decodeTime, delay);
if (status != kLibgav1StatusOk) {
ALOGE("av1 decoder failed to decode frame. status: %d.", status);
@@ -648,6 +653,24 @@
return false;
}
}
+
+ if (mHalPixelFormat != format) {
+ C2StreamPixelFormatInfo::output pixelFormat(0u, format);
+ std::vector<std::unique_ptr<C2SettingResult>> failures;
+ c2_status_t err = mIntf->config({&pixelFormat }, C2_MAY_BLOCK, &failures);
+ if (err == C2_OK) {
+ work->worklets.front()->output.configUpdate.push_back(
+ C2Param::Copy(pixelFormat));
+ } else {
+ ALOGE("Config update pixelFormat failed");
+ mSignalledError = true;
+ work->workletsProcessed = 1u;
+ work->result = C2_CORRUPTED;
+ return UNKNOWN_ERROR;
+ }
+ mHalPixelFormat = format;
+ }
+
C2MemoryUsage usage = {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
// We always create a graphic block that is width aligned to 16 and height
diff --git a/media/codec2/components/gav1/C2SoftGav1Dec.h b/media/codec2/components/gav1/C2SoftGav1Dec.h
index 134fa0d..4b13fef 100644
--- a/media/codec2/components/gav1/C2SoftGav1Dec.h
+++ b/media/codec2/components/gav1/C2SoftGav1Dec.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_C2_SOFT_GAV1_DEC_H_
#define ANDROID_C2_SOFT_GAV1_DEC_H_
+#include <inttypes.h>
+
#include <media/stagefright/foundation/ColorUtils.h>
#include <SimpleC2Component.h>
@@ -24,11 +26,6 @@
#include "libgav1/src/gav1/decoder.h"
#include "libgav1/src/gav1/decoder_settings.h"
-#define GETTIME(a, b) gettimeofday(a, b);
-#define TIME_DIFF(start, end, diff) \
- diff = (((end).tv_sec - (start).tv_sec) * 1000000) + \
- ((end).tv_usec - (start).tv_usec);
-
namespace android {
struct C2SoftGav1Dec : public SimpleC2Component {
@@ -54,6 +51,7 @@
std::shared_ptr<IntfImpl> mIntf;
std::unique_ptr<libgav1::Decoder> mCodecCtx;
+ uint32_t mHalPixelFormat;
uint32_t mWidth;
uint32_t mHeight;
bool mSignalledOutputEos;
@@ -80,8 +78,8 @@
}
} mBitstreamColorAspects;
- struct timeval mTimeStart; // Time at the start of decode()
- struct timeval mTimeEnd; // Time at the end of decode()
+ nsecs_t mTimeStart = 0; // Time at the start of decode()
+ nsecs_t mTimeEnd = 0; // Time at the end of decode()
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 2a6adca..5a660c5 100644
--- a/media/codec2/components/hevc/C2SoftHevcDec.cpp
+++ b/media/codec2/components/hevc/C2SoftHevcDec.cpp
@@ -663,8 +663,7 @@
void C2SoftHevcDec::resetPlugin() {
mSignalledOutputEos = false;
- gettimeofday(&mTimeStart, nullptr);
- gettimeofday(&mTimeEnd, nullptr);
+ mTimeStart = mTimeEnd = systemTime();
}
status_t C2SoftHevcDec::deleteDecoder() {
@@ -858,14 +857,13 @@
/* Decode header and get dimensions */
setParams(mStride, IVD_DECODE_HEADER);
}
- WORD32 delay;
- GETTIME(&mTimeStart, nullptr);
- TIME_DIFF(mTimeEnd, mTimeStart, delay);
+
+ mTimeStart = systemTime();
+ nsecs_t delay = mTimeStart - mTimeEnd;
(void) ivdec_api_function(mDecHandle, ps_decode_ip, ps_decode_op);
- WORD32 decodeTime;
- GETTIME(&mTimeEnd, nullptr);
- TIME_DIFF(mTimeStart, mTimeEnd, decodeTime);
- ALOGV("decodeTime=%6d delay=%6d numBytes=%6d", decodeTime, delay,
+ mTimeEnd = systemTime();
+ nsecs_t decodeTime = mTimeEnd - mTimeStart;
+ ALOGV("decodeTime=%6" PRId64 " delay=%6" PRId64 " numBytes=%6d", decodeTime, delay,
ps_decode_op->u4_num_bytes_consumed);
if (IVD_MEM_ALLOC_FAILED == (ps_decode_op->u4_error_code & IVD_ERROR_MASK)) {
ALOGE("allocation failure in decoder");
diff --git a/media/codec2/components/hevc/C2SoftHevcDec.h b/media/codec2/components/hevc/C2SoftHevcDec.h
index b9296e9..6abf69e 100644
--- a/media/codec2/components/hevc/C2SoftHevcDec.h
+++ b/media/codec2/components/hevc/C2SoftHevcDec.h
@@ -20,6 +20,7 @@
#include <media/stagefright/foundation/ColorUtils.h>
#include <atomic>
+#include <inttypes.h>
#include <SimpleC2Component.h>
#include "ihevc_typedefs.h"
@@ -41,10 +42,6 @@
#define IVDEXT_CMD_CTL_SET_NUM_CORES \
(IVD_CONTROL_API_COMMAND_TYPE_T)IHEVCD_CXA_CMD_CTL_SET_NUM_CORES
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
-#define GETTIME(a, b) gettimeofday(a, b);
-#define TIME_DIFF(start, end, diff) \
- diff = (((end).tv_sec - (start).tv_sec) * 1000000) + \
- ((end).tv_usec - (start).tv_usec);
struct C2SoftHevcDec : public SimpleC2Component {
@@ -142,8 +139,8 @@
} mBitstreamColorAspects;
// profile
- struct timeval mTimeStart;
- struct timeval mTimeEnd;
+ nsecs_t mTimeStart = 0;
+ nsecs_t mTimeEnd = 0;
C2_DO_NOT_COPY(C2SoftHevcDec);
};
diff --git a/media/codec2/components/hevc/C2SoftHevcEnc.cpp b/media/codec2/components/hevc/C2SoftHevcEnc.cpp
index 4f5caec..947e387 100644
--- a/media/codec2/components/hevc/C2SoftHevcEnc.cpp
+++ b/media/codec2/components/hevc/C2SoftHevcEnc.cpp
@@ -591,8 +591,7 @@
CREATE_DUMP_FILE(mInFile);
CREATE_DUMP_FILE(mOutFile);
- gettimeofday(&mTimeStart, nullptr);
- gettimeofday(&mTimeEnd, nullptr);
+ mTimeStart = mTimeEnd = systemTime();
}
C2SoftHevcEnc::~C2SoftHevcEnc() {
@@ -1203,11 +1202,11 @@
}
}
- uint64_t timeDelay = 0;
- uint64_t timeTaken = 0;
+ nsecs_t timeDelay = 0;
+ nsecs_t timeTaken = 0;
memset(&s_encode_op, 0, sizeof(s_encode_op));
- GETTIME(&mTimeStart, nullptr);
- TIME_DIFF(mTimeEnd, mTimeStart, timeDelay);
+ mTimeStart = systemTime();
+ timeDelay = mTimeStart - mTimeEnd;
if (inputBuffer) {
err = ihevce_encode(mCodecCtx, &s_encode_ip, &s_encode_op);
@@ -1222,12 +1221,12 @@
fillEmptyWork(work);
}
- GETTIME(&mTimeEnd, nullptr);
/* Compute time taken for decode() */
- TIME_DIFF(mTimeStart, mTimeEnd, timeTaken);
+ mTimeEnd = systemTime();
+ timeTaken = mTimeEnd - mTimeStart;
- ALOGV("timeTaken=%6d delay=%6d numBytes=%6d", (int)timeTaken,
- (int)timeDelay, s_encode_op.i4_bytes_generated);
+ ALOGV("timeTaken=%6" PRId64 " delay=%6" PRId64 " numBytes=%6d", timeTaken,
+ timeDelay, s_encode_op.i4_bytes_generated);
if (s_encode_op.i4_bytes_generated) {
finishWork(s_encode_op.u8_pts, work, pool, &s_encode_op);
diff --git a/media/codec2/components/hevc/C2SoftHevcEnc.h b/media/codec2/components/hevc/C2SoftHevcEnc.h
index 4217a8b..ce9cec8 100644
--- a/media/codec2/components/hevc/C2SoftHevcEnc.h
+++ b/media/codec2/components/hevc/C2SoftHevcEnc.h
@@ -19,6 +19,7 @@
#include <SimpleC2Component.h>
#include <algorithm>
+#include <inttypes.h>
#include <map>
#include <media/stagefright/foundation/ColorUtils.h>
#include <utils/Vector.h>
@@ -27,14 +28,6 @@
namespace android {
-/** Get time */
-#define GETTIME(a, b) gettimeofday(a, b)
-
-/** Compute difference between start and end */
-#define TIME_DIFF(start, end, diff) \
- diff = (((end).tv_sec - (start).tv_sec) * 1000000) + \
- ((end).tv_usec - (start).tv_usec);
-
#define CODEC_MAX_CORES 4
#define MAX_B_FRAMES 1
#define MAX_RC_LOOKAHEAD 1
@@ -102,8 +95,8 @@
#endif /* FILE_DUMP_ENABLE */
// profile
- struct timeval mTimeStart;
- struct timeval mTimeEnd;
+ nsecs_t mTimeStart = 0;
+ nsecs_t mTimeEnd = 0;
c2_status_t initEncParams();
c2_status_t initEncoder();
@@ -127,14 +120,12 @@
#define OUTPUT_DUMP_EXT "h265"
#define GENERATE_FILE_NAMES() \
{ \
- GETTIME(&mTimeStart, NULL); \
- strcpy(mInFile, ""); \
+ nsecs_t now = systemTime(); \
ALOGD("GENERATE_FILE_NAMES"); \
- sprintf(mInFile, "%s_%ld.%ld.%s", INPUT_DUMP_PATH, mTimeStart.tv_sec, \
- mTimeStart.tv_usec, INPUT_DUMP_EXT); \
- strcpy(mOutFile, ""); \
- sprintf(mOutFile, "%s_%ld.%ld.%s", OUTPUT_DUMP_PATH, \
- mTimeStart.tv_sec, mTimeStart.tv_usec, OUTPUT_DUMP_EXT); \
+ sprintf(mInFile, "%s_%" PRId64 ".%s", INPUT_DUMP_PATH, \
+ mTimeStart, INPUT_DUMP_EXT); \
+ sprintf(mutFile, "%s_%" PRId64 ".%s", OUTPUT_DUMP_PATH, \
+ mTimeStart, OUTPUT_DUMP_EXT); \
}
#define CREATE_DUMP_FILE(m_filename) \
diff --git a/media/codec2/components/mpeg2/C2SoftMpeg2Dec.cpp b/media/codec2/components/mpeg2/C2SoftMpeg2Dec.cpp
index 5f9b30b..9a41910 100644
--- a/media/codec2/components/mpeg2/C2SoftMpeg2Dec.cpp
+++ b/media/codec2/components/mpeg2/C2SoftMpeg2Dec.cpp
@@ -731,8 +731,7 @@
void C2SoftMpeg2Dec::resetPlugin() {
mSignalledOutputEos = false;
- gettimeofday(&mTimeStart, nullptr);
- gettimeofday(&mTimeEnd, nullptr);
+ mTimeStart = mTimeEnd = systemTime();
}
status_t C2SoftMpeg2Dec::deleteDecoder() {
@@ -929,14 +928,12 @@
}
// If input dump is enabled, then write to file
DUMP_TO_FILE(mInFile, s_decode_ip.pv_stream_buffer, s_decode_ip.u4_num_Bytes);
- WORD32 delay;
- GETTIME(&mTimeStart, nullptr);
- TIME_DIFF(mTimeEnd, mTimeStart, delay);
+ nsecs_t delay = mTimeStart - mTimeEnd;
(void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op);
- WORD32 decodeTime;
- GETTIME(&mTimeEnd, nullptr);
- TIME_DIFF(mTimeStart, mTimeEnd, decodeTime);
- ALOGV("decodeTime=%6d delay=%6d numBytes=%6d ", decodeTime, delay,
+
+ mTimeEnd = systemTime();
+ nsecs_t decodeTime = mTimeEnd - mTimeStart;
+ ALOGV("decodeTime=%" PRId64 " delay=%" PRId64 " numBytes=%6d ", decodeTime, delay,
s_decode_op.u4_num_bytes_consumed);
if (IMPEG2D_UNSUPPORTED_DIMENSIONS == s_decode_op.u4_error_code) {
ALOGV("unsupported resolution : %dx%d", s_decode_op.u4_pic_wd, s_decode_op.u4_pic_ht);
diff --git a/media/codec2/components/mpeg2/C2SoftMpeg2Dec.h b/media/codec2/components/mpeg2/C2SoftMpeg2Dec.h
index 8a29c14..3965bcc 100644
--- a/media/codec2/components/mpeg2/C2SoftMpeg2Dec.h
+++ b/media/codec2/components/mpeg2/C2SoftMpeg2Dec.h
@@ -18,6 +18,7 @@
#define ANDROID_C2_SOFT_MPEG2_DEC_H_
#include <atomic>
+#include <inttypes.h>
#include <SimpleC2Component.h>
#include <media/stagefright/foundation/ColorUtils.h>
@@ -42,19 +43,14 @@
#define IVDEXT_CMD_CTL_SET_NUM_CORES \
(IVD_CONTROL_API_COMMAND_TYPE_T)IMPEG2D_CMD_CTL_SET_NUM_CORES
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
-#define GETTIME(a, b) gettimeofday(a, b);
-#define TIME_DIFF(start, end, diff) \
- diff = (((end).tv_sec - (start).tv_sec) * 1000000) + \
- ((end).tv_usec - (start).tv_usec);
#ifdef FILE_DUMP_ENABLE
#define INPUT_DUMP_PATH "/sdcard/clips/mpeg2d_input"
#define INPUT_DUMP_EXT "m2v"
#define GENERATE_FILE_NAMES() { \
- GETTIME(&mTimeStart, NULL); \
- strcpy(mInFile, ""); \
- sprintf(mInFile, "%s_%ld.%ld.%s", INPUT_DUMP_PATH, \
- mTimeStart.tv_sec, mTimeStart.tv_usec, \
+ nsecs_t now = systemTime(); \
+ sprintf(mInFile, "%s_%" PRId64 ".%s", \
+ INPUT_DUMP_PATH, now, \
INPUT_DUMP_EXT); \
}
#define CREATE_DUMP_FILE(m_filename) { \
@@ -183,8 +179,8 @@
} mBitstreamColorAspects;
// profile
- struct timeval mTimeStart;
- struct timeval mTimeEnd;
+ nsecs_t mTimeStart = 0;
+ nsecs_t mTimeEnd = 0;
#ifdef FILE_DUMP_ENABLE
char mInFile[200];
#endif /* FILE_DUMP_ENABLE */
diff --git a/media/codec2/components/vpx/C2SoftVpxDec.cpp b/media/codec2/components/vpx/C2SoftVpxDec.cpp
index 5fc89be..e81f044 100644
--- a/media/codec2/components/vpx/C2SoftVpxDec.cpp
+++ b/media/codec2/components/vpx/C2SoftVpxDec.cpp
@@ -19,7 +19,6 @@
#include <log/log.h>
#include <algorithm>
-
#include <media/stagefright/foundation/AUtils.h>
#include <media/stagefright/foundation/MediaDefs.h>
@@ -218,11 +217,20 @@
.build());
// TODO: support more formats?
+ std::vector<uint32_t> pixelFormats = {HAL_PIXEL_FORMAT_YCBCR_420_888};
+#ifdef VP9
+ if (isAtLeastT()) {
+ pixelFormats.push_back(HAL_PIXEL_FORMAT_YCBCR_P010);
+ }
+#endif
addParameter(
DefineParam(mPixelFormat, C2_PARAMKEY_PIXEL_FORMAT)
- .withConstValue(new C2StreamPixelFormatInfo::output(
- 0u, HAL_PIXEL_FORMAT_YCBCR_420_888))
+ .withDefault(new C2StreamPixelFormatInfo::output(
+ 0u, HAL_PIXEL_FORMAT_YCBCR_420_888))
+ .withFields({C2F(mPixelFormat, value).oneOf(pixelFormats)})
+ .withSetter((Setter<decltype(*mPixelFormat)>::StrictValueWithNoDeps))
.build());
+
}
static C2R SizeSetter(bool mayBlock, const C2P<C2StreamPictureSizeInfo::output> &oldMe,
@@ -424,7 +432,7 @@
#else
mMode = MODE_VP8;
#endif
-
+ mHalPixelFormat = HAL_PIXEL_FORMAT_YV12;
mWidth = 320;
mHeight = 240;
mFrameParallelMode = false;
@@ -690,6 +698,24 @@
}
format = getHalPixelFormatForBitDepth10(allowRGBA1010102);
}
+
+ if (mHalPixelFormat != format) {
+ C2StreamPixelFormatInfo::output pixelFormat(0u, format);
+ std::vector<std::unique_ptr<C2SettingResult>> failures;
+ c2_status_t err = mIntf->config({&pixelFormat }, C2_MAY_BLOCK, &failures);
+ if (err == C2_OK) {
+ work->worklets.front()->output.configUpdate.push_back(
+ C2Param::Copy(pixelFormat));
+ } else {
+ ALOGE("Config update pixelFormat failed");
+ mSignalledError = true;
+ work->workletsProcessed = 1u;
+ work->result = C2_CORRUPTED;
+ return UNKNOWN_ERROR;
+ }
+ mHalPixelFormat = format;
+ }
+
C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
c2_status_t err = pool->fetchGraphicBlock(align(mWidth, 16), mHeight, format, usage, &block);
if (err != C2_OK) {
diff --git a/media/codec2/components/vpx/C2SoftVpxDec.h b/media/codec2/components/vpx/C2SoftVpxDec.h
index 2065165..5564766 100644
--- a/media/codec2/components/vpx/C2SoftVpxDec.h
+++ b/media/codec2/components/vpx/C2SoftVpxDec.h
@@ -67,6 +67,7 @@
vpx_codec_ctx_t *mCodecCtx;
bool mFrameParallelMode; // Frame parallel is only supported by VP9 decoder.
+ uint32_t mHalPixelFormat;
uint32_t mWidth;
uint32_t mHeight;
bool mSignalledOutputEos;
diff --git a/media/codec2/fuzzer/Android.bp b/media/codec2/fuzzer/Android.bp
index 3adc212..147a52e 100644
--- a/media/codec2/fuzzer/Android.bp
+++ b/media/codec2/fuzzer/Android.bp
@@ -38,6 +38,12 @@
"-Wall",
"-Werror",
],
+
+ fuzz_config: {
+ cc: [
+ "wonsik@google.com",
+ ],
+ },
}
cc_fuzz {
diff --git a/media/codec2/sfplugin/Android.bp b/media/codec2/sfplugin/Android.bp
index a73b493..c36ae94 100644
--- a/media/codec2/sfplugin/Android.bp
+++ b/media/codec2/sfplugin/Android.bp
@@ -67,6 +67,7 @@
"libstagefright_codecbase",
"libstagefright_foundation",
"libstagefright_omx",
+ "libstagefright_surface_utils",
"libstagefright_xmlparser",
"libui",
"libutils",
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 3302dd3..19bb206 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -30,6 +30,7 @@
#include <android/hardware/media/c2/1.0/IInputSurface.h>
#include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
#include <android/hardware/media/omx/1.0/IOmx.h>
+#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <cutils/properties.h>
#include <gui/IGraphicBufferProducer.h>
@@ -871,6 +872,11 @@
}
config->mTunneled = true;
}
+
+ int32_t pushBlankBuffersOnStop = 0;
+ if (msg->findInt32(KEY_PUSH_BLANK_BUFFERS_ON_STOP, &pushBlankBuffersOnStop)) {
+ config->mPushBlankBuffersOnStop = pushBlankBuffersOnStop == 1;
+ }
}
}
setSurface(surface);
@@ -1006,7 +1012,9 @@
// Query vendor format for Flexible YUV
std::vector<std::unique_ptr<C2Param>> heapParams;
C2StoreFlexiblePixelFormatDescriptorsInfo *pixelFormatInfo = nullptr;
- if (mClient->query(
+ int vendorSdkVersion = base::GetIntProperty(
+ "ro.vendor.build.version.sdk", android_get_device_api_level());
+ if (vendorSdkVersion >= __ANDROID_API_S__ && mClient->query(
{},
{C2StoreFlexiblePixelFormatDescriptorsInfo::PARAM_TYPE},
C2_MAY_BLOCK,
@@ -1066,6 +1074,17 @@
}
} else {
if ((config->mDomain & Config::IS_ENCODER) || !surface) {
+ if (vendorSdkVersion < __ANDROID_API_S__ &&
+ (format == COLOR_FormatYUV420Flexible ||
+ format == COLOR_FormatYUV420Planar ||
+ format == COLOR_FormatYUV420PackedPlanar ||
+ format == COLOR_FormatYUV420SemiPlanar ||
+ format == COLOR_FormatYUV420PackedSemiPlanar)) {
+ // pre-S framework used to map these color formats into YV12.
+ // Codecs from older vendor partition may be relying on
+ // this assumption.
+ format = HAL_PIXEL_FORMAT_YV12;
+ }
switch (format) {
case COLOR_FormatYUV420Flexible:
format = COLOR_FormatYUV420Planar;
@@ -1526,6 +1545,9 @@
using namespace android::hardware::graphics::bufferqueue::V1_0::utils;
typedef android::hardware::media::omx::V1_0::Status OmxStatus;
android::sp<IOmx> omx = IOmx::getService();
+ if (omx == nullptr) {
+ return nullptr;
+ }
typedef android::hardware::graphics::bufferqueue::V1_0::
IGraphicBufferProducer HGraphicBufferProducer;
typedef android::hardware::media::omx::V1_0::
@@ -1804,15 +1826,13 @@
return;
}
- err2 = mChannel->requestInitialInputBuffers();
-
- if (err2 != OK) {
- ALOGE("Initial request for Input Buffers failed");
- mCallback->onError(err2,ACTION_CODE_FATAL);
- return;
- }
mCallback->onStartCompleted();
+ err2 = mChannel->requestInitialInputBuffers();
+ if (err2 != OK) {
+ ALOGE("Initial request for Input Buffers failed");
+ mCallback->onError(err2, ACTION_CODE_FATAL);
+ }
}
void CCodec::initiateShutdown(bool keepComponentAllocated) {
@@ -1838,7 +1858,13 @@
}
state->set(STOPPING);
}
-
+ {
+ Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
+ const std::unique_ptr<Config> &config = *configLocked;
+ if (config->mPushBlankBuffersOnStop) {
+ mChannel->pushBlankBufferToOutputSurface();
+ }
+ }
mChannel->reset();
(new AMessage(kWhatStop, this))->post();
}
@@ -1926,6 +1952,13 @@
config->mInputSurfaceDataspace = HAL_DATASPACE_UNKNOWN;
}
}
+ {
+ Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
+ const std::unique_ptr<Config> &config = *configLocked;
+ if (config->mPushBlankBuffersOnStop) {
+ mChannel->pushBlankBufferToOutputSurface();
+ }
+ }
mChannel->reset();
// thiz holds strong ref to this while the thread is running.
@@ -2093,7 +2126,11 @@
state->set(RUNNING);
}
- (void)mChannel->requestInitialInputBuffers();
+ status_t err = mChannel->requestInitialInputBuffers();
+ if (err != OK) {
+ ALOGE("Resume request for Input Buffers failed");
+ mCallback->onError(err, ACTION_CODE_FATAL);
+ }
}
void CCodec::signalSetParameters(const sp<AMessage> &msg) {
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 674714f..62a1d02 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -15,6 +15,7 @@
*/
//#define LOG_NDEBUG 0
+#include <utils/Errors.h>
#define LOG_TAG "CCodecBufferChannel"
#define ATRACE_TAG ATRACE_TAG_VIDEO
#include <utils/Log.h>
@@ -48,6 +49,7 @@
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/MediaCodecConstants.h>
#include <media/stagefright/SkipCutBuffer.h>
+#include <media/stagefright/SurfaceUtils.h>
#include <media/MediaCodecBuffer.h>
#include <mediadrm/ICrypto.h>
#include <system/window.h>
@@ -2096,12 +2098,13 @@
}
PipelineWatcher::Clock::duration CCodecBufferChannel::elapsed() {
- // When client pushed EOS, we want all the work to be done quickly.
// Otherwise, component may have stalled work due to input starvation up to
// the sum of the delay in the pipeline.
+ // TODO(b/231253301): When client pushed EOS, the pipeline could have less
+ // number of frames.
size_t n = 0;
- if (!mInputMetEos) {
- size_t outputDelay = mOutput.lock()->outputDelay;
+ size_t outputDelay = mOutput.lock()->outputDelay;
+ {
Mutexed<Input>::Locked input(mInput);
n = input->inputDelay + input->pipelineDelay + outputDelay;
}
@@ -2180,4 +2183,13 @@
}
}
+status_t CCodecBufferChannel::pushBlankBufferToOutputSurface() {
+ Mutexed<OutputSurface>::Locked output(mOutputSurface);
+ sp<ANativeWindow> nativeWindow = static_cast<ANativeWindow *>(output->surface.get());
+ if (nativeWindow == nullptr) {
+ return INVALID_OPERATION;
+ }
+ return pushBlankBuffersToNativeWindow(nativeWindow.get());
+}
+
} // namespace android
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.h b/media/codec2/sfplugin/CCodecBufferChannel.h
index 26eef30..b3a5f4b 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.h
+++ b/media/codec2/sfplugin/CCodecBufferChannel.h
@@ -181,6 +181,11 @@
void setMetaMode(MetaMode mode);
+ /**
+ * Push a blank buffer to the configured native output surface.
+ */
+ status_t pushBlankBufferToOutputSurface();
+
private:
class QueueGuard;
diff --git a/media/codec2/sfplugin/CCodecConfig.cpp b/media/codec2/sfplugin/CCodecConfig.cpp
index c15b5ca..f3fb5ff 100644
--- a/media/codec2/sfplugin/CCodecConfig.cpp
+++ b/media/codec2/sfplugin/CCodecConfig.cpp
@@ -20,6 +20,8 @@
#include <log/log.h>
#include <utils/NativeHandle.h>
+#include <android-base/properties.h>
+
#include <C2Component.h>
#include <C2Param.h>
#include <util/C2InterfaceHelper.h>
@@ -324,7 +326,8 @@
: mInputFormat(new AMessage),
mOutputFormat(new AMessage),
mUsingSurface(false),
- mTunneled(false) { }
+ mTunneled(false),
+ mPushBlankBuffersOnStop(false) { }
void CCodecConfig::initializeStandardParams() {
typedef Domain D;
@@ -963,8 +966,6 @@
.limitTo(D::ENCODER & D::VIDEO & D::READ));
/* still to do
- constexpr char KEY_PUSH_BLANK_BUFFERS_ON_STOP[] = "push-blank-buffers-on-shutdown";
-
not yet used by MediaCodec, but defined as MediaFormat
KEY_AUDIO_SESSION_ID // we use "audio-hw-sync"
KEY_OUTPUT_REORDER_DEPTH
@@ -1071,6 +1072,13 @@
C2_PARAMKEY_SURFACE_SCALING_MODE);
} else {
addLocalParam(new C2StreamColorAspectsInfo::input(0u), C2_PARAMKEY_COLOR_ASPECTS);
+
+ if (domain.value == C2Component::DOMAIN_VIDEO) {
+ addLocalParam(new C2AndroidStreamAverageBlockQuantizationInfo::output(0u, 0),
+ C2_PARAMKEY_AVERAGE_QP);
+ addLocalParam(new C2StreamPictureTypeMaskInfo::output(0u, 0),
+ C2_PARAMKEY_PICTURE_TYPE);
+ }
}
}
@@ -1112,15 +1120,21 @@
const std::shared_ptr<Codec2Client::Configurable> &configurable,
const std::vector<C2Param::Index> &indices,
c2_blocking_t blocking) {
+ static const int32_t kProductFirstApiLevel =
+ base::GetIntProperty<int32_t>("ro.product.first_api_level", 0);
+ static const int32_t kBoardApiLevel =
+ base::GetIntProperty<int32_t>("ro.board.first_api_level", 0);
+ static const int32_t kFirstApiLevel =
+ (kBoardApiLevel != 0) ? kBoardApiLevel : kProductFirstApiLevel;
mSubscribedIndices.insert(indices.begin(), indices.end());
- // TODO: enable this when components no longer crash on this config
- if (mSubscribedIndices.size() != mSubscribedIndicesSize && false) {
- std::vector<uint32_t> indices;
+ if (mSubscribedIndices.size() != mSubscribedIndicesSize
+ && kFirstApiLevel >= __ANDROID_API_T__) {
+ std::vector<uint32_t> indicesVector;
for (C2Param::Index ix : mSubscribedIndices) {
- indices.push_back(ix);
+ indicesVector.push_back(ix);
}
std::unique_ptr<C2SubscribedParamIndicesTuning> subscribeTuning =
- C2SubscribedParamIndicesTuning::AllocUnique(indices);
+ C2SubscribedParamIndicesTuning::AllocUnique(indicesVector);
std::vector<std::unique_ptr<C2SettingResult>> results;
c2_status_t c2Err = configurable->config({ subscribeTuning.get() }, blocking, &results);
if (c2Err != C2_OK && c2Err != C2_BAD_INDEX) {
diff --git a/media/codec2/sfplugin/CCodecConfig.h b/media/codec2/sfplugin/CCodecConfig.h
index 88e6239..2e7b866 100644
--- a/media/codec2/sfplugin/CCodecConfig.h
+++ b/media/codec2/sfplugin/CCodecConfig.h
@@ -148,6 +148,8 @@
bool mTunneled;
sp<NativeHandle> mSidebandHandle;
+ bool mPushBlankBuffersOnStop;
+
CCodecConfig();
/// initializes the members required to manage the format: descriptors, reflector,
@@ -396,4 +398,3 @@
} // namespace android
#endif // C_CODEC_H_
-
diff --git a/media/codec2/vndk/C2AllocatorIon.cpp b/media/codec2/vndk/C2AllocatorIon.cpp
index 7b593ee..a6a733e 100644
--- a/media/codec2/vndk/C2AllocatorIon.cpp
+++ b/media/codec2/vndk/C2AllocatorIon.cpp
@@ -31,6 +31,7 @@
#include <C2HandleIonInternal.h>
#include <android-base/properties.h>
+#include <media/stagefright/foundation/Mutexed.h>
namespace android {
@@ -180,7 +181,7 @@
c2_status_t map(size_t offset, size_t size, C2MemoryUsage usage, C2Fence *fence, void **addr) {
(void)fence; // TODO: wait for fence
*addr = nullptr;
- if (!mMappings.empty()) {
+ if (!mMappings.lock()->empty()) {
ALOGV("multiple map");
// TODO: technically we should return DUPLICATE here, but our block views don't
// actually unmap, so we end up remapping an ion buffer multiple times.
@@ -207,47 +208,44 @@
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);
+ mMappings.lock()->push_back(map);
}
return err;
}
c2_status_t unmap(void *addr, size_t size, C2Fence *fence) {
- if (mMappings.empty()) {
+ Mutexed<std::list<Mapping>>::Locked mappings(mMappings);
+ if (mappings->empty()) {
ALOGD("tried to unmap unmapped buffer");
return C2_NOT_FOUND;
}
- { // 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;
+ for (auto it = mappings->begin(); it != mappings->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)mappings->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;
}
virtual ~Impl() {
- if (!mMappings.empty()) {
+ Mutexed<std::list<Mapping>>::Locked mappings(mMappings);
+ if (!mappings->empty()) {
ALOGD("Dangling mappings!");
- std::lock_guard<std::mutex> guard(mMutexMappings);
- for (const Mapping &map : mMappings) {
+ for (const Mapping &map : *mappings) {
(void)munmap(map.addr, map.size);
}
}
@@ -325,8 +323,7 @@
size_t alignmentBytes;
size_t size;
};
- std::list<Mapping> mMappings;
- std::mutex mMutexMappings;
+ Mutexed<std::list<Mapping>> mMappings;
};
class C2AllocationIon::ImplV2 : public C2AllocationIon::Impl {
diff --git a/media/codec2/vndk/C2DmaBufAllocator.cpp b/media/codec2/vndk/C2DmaBufAllocator.cpp
index 1aa3d69..c470171 100644
--- a/media/codec2/vndk/C2DmaBufAllocator.cpp
+++ b/media/codec2/vndk/C2DmaBufAllocator.cpp
@@ -31,6 +31,7 @@
#include <list>
#include <android-base/properties.h>
+#include <media/stagefright/foundation/Mutexed.h>
namespace android {
@@ -161,7 +162,7 @@
size_t alignmentBytes;
size_t size;
};
- std::list<Mapping> mMappings;
+ Mutexed<std::list<Mapping>> mMappings;
// TODO: we could make this encapsulate shared_ptr and copiable
C2_DO_NOT_COPY(C2DmaBufAllocation);
@@ -171,7 +172,7 @@
void** addr) {
(void)fence; // TODO: wait for fence
*addr = nullptr;
- if (!mMappings.empty()) {
+ if (!mMappings.lock()->empty()) {
ALOGV("multiple map");
// TODO: technically we should return DUPLICATE here, but our block views
// don't actually unmap, so we end up remapping the buffer multiple times.
@@ -199,17 +200,18 @@
c2_status_t err =
mapInternal(mapSize, mapOffset, alignmentBytes, prot, flags, &(map.addr), addr);
if (map.addr) {
- mMappings.push_back(map);
+ mMappings.lock()->push_back(map);
}
return err;
}
c2_status_t C2DmaBufAllocation::unmap(void* addr, size_t size, C2Fence* fence) {
- if (mMappings.empty()) {
+ Mutexed<std::list<Mapping>>::Locked mappings(mMappings);
+ if (mappings->empty()) {
ALOGD("tried to unmap unmapped buffer");
return C2_NOT_FOUND;
}
- for (auto it = mMappings.begin(); it != mMappings.end(); ++it) {
+ for (auto it = mappings->begin(); it != mappings->end(); ++it) {
if (addr != (uint8_t*)it->addr + it->alignmentBytes ||
size + it->alignmentBytes != it->size) {
continue;
@@ -222,7 +224,7 @@
if (fence) {
*fence = C2Fence(); // not using fences
}
- (void)mMappings.erase(it);
+ (void)mappings->erase(it);
ALOGV("successfully unmapped: %d", mHandle.bufferFd());
return C2_OK;
}
@@ -253,9 +255,10 @@
}
C2DmaBufAllocation::~C2DmaBufAllocation() {
- if (!mMappings.empty()) {
+ Mutexed<std::list<Mapping>>::Locked mappings(mMappings);
+ if (!mappings->empty()) {
ALOGD("Dangling mappings!");
- for (const Mapping& map : mMappings) {
+ for (const Mapping& map : *mappings) {
int err = munmap(map.addr, map.size);
if (err) ALOGD("munmap failed");
}
diff --git a/media/codec2/vndk/platform/C2BqBuffer.cpp b/media/codec2/vndk/platform/C2BqBuffer.cpp
index 2cca3c8..63b0f39 100644
--- a/media/codec2/vndk/platform/C2BqBuffer.cpp
+++ b/media/codec2/vndk/platform/C2BqBuffer.cpp
@@ -576,14 +576,7 @@
}
~Impl() {
- bool noInit = false;
for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
- if (!noInit && mProducer) {
- Return<HStatus> transResult =
- mProducer->detachBuffer(static_cast<int32_t>(i));
- noInit = !transResult.isOk() ||
- static_cast<HStatus>(transResult) == HStatus::NO_INIT;
- }
mBuffers[i].clear();
}
}
@@ -692,15 +685,6 @@
{
sp<GraphicBuffer> buffers[NUM_BUFFER_SLOTS];
std::scoped_lock<std::mutex> lock(mMutex);
- bool noInit = false;
- for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
- if (!noInit && mProducer) {
- Return<HStatus> transResult =
- mProducer->detachBuffer(static_cast<int32_t>(i));
- noInit = !transResult.isOk() ||
- static_cast<HStatus>(transResult) == HStatus::NO_INIT;
- }
- }
int32_t oldGeneration = mGeneration;
if (producer) {
mProducer = producer;
diff --git a/media/libaaudio/fuzzer/Android.bp b/media/libaaudio/fuzzer/Android.bp
index e2eec7a..2a12191 100644
--- a/media/libaaudio/fuzzer/Android.bp
+++ b/media/libaaudio/fuzzer/Android.bp
@@ -36,11 +36,11 @@
"libaudiomanager",
"libaudiopolicy",
"libaudioclient_aidl_conversion",
+ "libutils",
],
static_libs: [
"android.media.audio.common.types-V1-cpp",
"liblog",
- "libutils",
"libcutils",
"libaaudio",
"libjsoncpp",
diff --git a/media/libaaudio/scripts/measure_device_power.py b/media/libaaudio/scripts/measure_device_power.py
index fd7f85f..1f90933 100755
--- a/media/libaaudio/scripts/measure_device_power.py
+++ b/media/libaaudio/scripts/measure_device_power.py
@@ -79,28 +79,42 @@
SORTED_ENERGY_LIST = sorted(ENERGY_DICTIONARY, key=ENERGY_DICTIONARY.get)
-# Sometimes "adb unroot" returns 1!
+# Sometimes adb returns 1 for no apparent reason.
# So try several times.
# @return 0 on success
-def adbUnroot():
+def adbTryMultiple(command):
returnCode = 1
count = 0
limit = 5
while count < limit and returnCode != 0:
- print(('Try to adb unroot {} of {}'.format(count, limit)))
+ print(('Try to adb {} {} of {}'.format(command, count, limit)))
subprocess.call(["adb", "wait-for-device"])
time.sleep(PRE_DELAY_SECONDS)
- returnCode = subprocess.call(["adb", "unroot"])
+ returnCode = subprocess.call(["adb", command])
print(('returnCode = {}'.format(returnCode)))
count += 1
return returnCode
+# Sometimes "adb root" returns 1!
+# So try several times.
+# @return 0 on success
+def adbRoot():
+ return adbTryMultiple("root");
+
+# Sometimes "adb unroot" returns 1!
+# So try several times.
+# @return 0 on success
+def adbUnroot():
+ return adbTryMultiple("unroot");
+
# @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()
+ elif commandString == "adb root":
+ result = adbRoot()
else:
commandArray = commandString.split(' ')
result = subprocess.run(commandArray, check=True, capture_output=True).stdout
@@ -111,6 +125,8 @@
def adbCommand(commandString):
if commandString == "unroot":
result = adbUnroot()
+ elif commandString == "root":
+ result = adbRoot()
else:
print(("adb " + commandString))
commandArray = ["adb"] + commandString.split(' ')
@@ -230,7 +246,7 @@
print((command + "\n"))
comment = command[1:].strip() # remove leading '#'
elif command.endswith('\\'):
- command = command[:-1].strip() # remove \\
+ command = command[:-1].strip() # remove trailing '\'
runCommand(command)
elif command:
report = averageEnergyForCommand(command, DEFAULT_NUM_ITERATIONS)
diff --git a/media/libaaudio/scripts/synthmark_tests.txt b/media/libaaudio/scripts/synthmark_tests.txt
index 24e719d..8b6d47e 100644
--- a/media/libaaudio/scripts/synthmark_tests.txt
+++ b/media/libaaudio/scripts/synthmark_tests.txt
@@ -1,31 +1,36 @@
# Measure energy consumption with synthmark.
-# ADPF <400 RR
-adb root \
-adb shell setprop vendor.powerhal.adpf.uclamp_min.high_limit 400 \
-adb shell synthmark -tj -n1 -N50 -B2 -z1
-adb shell synthmark -tj -n1 -N75 -B2 -z1
-adb shell synthmark -tj -n1 -N100 -B2 -z1
-
-# ADPF <500 RR
-adb root \
-adb shell setprop vendor.powerhal.adpf.uclamp_min.high_limit 500 \
-adb shell synthmark -tj -n1 -N50 -B2 -z1
-adb shell synthmark -tj -n1 -N75 -B2 -z1
-adb shell synthmark -tj -n1 -N100 -B2 -z1
-
-# ADPF <600 RR
-adb root \
-adb shell setprop vendor.powerhal.adpf.uclamp_min.high_limit 600 \
-adb shell synthmark -tj -n1 -N50 -B2 -z1
-adb shell synthmark -tj -n1 -N75 -B2 -z1
-adb shell synthmark -tj -n1 -N100 -B2 -z1
-
# None
adb shell synthmark -tj -n1 -N50 -B2 -z0
adb shell synthmark -tj -n1 -N75 -B2 -z0
adb shell synthmark -tj -n1 -N100 -B2 -z0
+# ADPF PID
+adb shell synthmark -tj -n1 -N50 -B2 -z1
+adb shell synthmark -tj -n1 -N75 -B2 -z1
+adb shell synthmark -tj -n1 -N100 -B2 -z1
+
+# ADPF <400 RR
+# adb root \
+# adb shell setprop vendor.powerhal.adpf.uclamp_min.high_limit 400 \
+# adb shell synthmark -tj -n1 -N50 -B2 -z1
+# adb shell synthmark -tj -n1 -N75 -B2 -z1
+# adb shell synthmark -tj -n1 -N100 -B2 -z1
+
+# ADPF <500 RR
+# adb root \
+# adb shell setprop vendor.powerhal.adpf.uclamp_min.high_limit 500 \
+# adb shell synthmark -tj -n1 -N50 -B2 -z1
+# adb shell synthmark -tj -n1 -N75 -B2 -z1
+# adb shell synthmark -tj -n1 -N100 -B2 -z1
+
+# ADPF <600 RR
+# adb root \
+# adb shell setprop vendor.powerhal.adpf.uclamp_min.high_limit 600 \
+# adb shell synthmark -tj -n1 -N50 -B2 -z1
+# adb shell synthmark -tj -n1 -N75 -B2 -z1
+# adb shell synthmark -tj -n1 -N100 -B2 -z1
+
# uclamp
# adb root \
# adb shell synthmark -tj -n1 -N75 -B2 -u1
diff --git a/media/libaaudio/src/Android.bp b/media/libaaudio/src/Android.bp
index f50b53a..363d219 100644
--- a/media/libaaudio/src/Android.bp
+++ b/media/libaaudio/src/Android.bp
@@ -93,7 +93,6 @@
"-Wno-unused-parameter",
"-Wall",
"-Werror",
-
// By default, all symbols are hidden.
// "-fvisibility=hidden",
// AAUDIO_API is used to explicitly export a function or a variable as a visible symbol.
@@ -261,7 +260,7 @@
"binding/aidl/aaudio/IAAudioService.aidl",
],
imports: [
- "android.media.audio.common.types",
+ "android.media.audio.common.types-V1",
"audioclient-types-aidl",
"shared-file-region-aidl",
"framework-permission-aidl",
diff --git a/media/libaaudio/src/client/AAudioFlowGraph.cpp b/media/libaaudio/src/client/AAudioFlowGraph.cpp
index d0c3238..2ed3e3c 100644
--- a/media/libaaudio/src/client/AAudioFlowGraph.cpp
+++ b/media/libaaudio/src/client/AAudioFlowGraph.cpp
@@ -35,7 +35,7 @@
#include <flowgraph/SourceI24.h>
#include <flowgraph/SourceI32.h>
-using namespace flowgraph;
+using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
aaudio_result_t AAudioFlowGraph::configure(audio_format_t sourceFormat,
int32_t sourceChannelCount,
diff --git a/media/libaaudio/src/client/AAudioFlowGraph.h b/media/libaaudio/src/client/AAudioFlowGraph.h
index 00b6575..602c17f 100644
--- a/media/libaaudio/src/client/AAudioFlowGraph.h
+++ b/media/libaaudio/src/client/AAudioFlowGraph.h
@@ -72,17 +72,19 @@
void setRampLengthInFrames(int32_t numFrames);
private:
- std::unique_ptr<flowgraph::FlowGraphSourceBuffered> mSource;
- std::unique_ptr<flowgraph::MonoBlend> mMonoBlend;
- 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;
+ std::unique_ptr<FLOWGRAPH_OUTER_NAMESPACE::flowgraph::FlowGraphSourceBuffered> mSource;
+ std::unique_ptr<FLOWGRAPH_OUTER_NAMESPACE::flowgraph::MonoBlend> mMonoBlend;
+ std::unique_ptr<FLOWGRAPH_OUTER_NAMESPACE::flowgraph::ClipToRange> mClipper;
+ std::unique_ptr<FLOWGRAPH_OUTER_NAMESPACE::flowgraph::MonoToMultiConverter> mChannelConverter;
+ std::unique_ptr<FLOWGRAPH_OUTER_NAMESPACE::flowgraph::ManyToMultiConverter>
+ mManyToMultiConverter;
+ std::unique_ptr<FLOWGRAPH_OUTER_NAMESPACE::flowgraph::MultiToManyConverter>
+ mMultiToManyConverter;
+ std::vector<std::unique_ptr<FLOWGRAPH_OUTER_NAMESPACE::flowgraph::RampLinear>> mVolumeRamps;
+ std::vector<float> mPanningVolumes;
+ float mTargetVolume = 1.0f;
+ android::audio_utils::Balance mBalance;
+ std::unique_ptr<FLOWGRAPH_OUTER_NAMESPACE::flowgraph::FlowGraphSink> mSink;
};
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
index 450d390..7c7a969 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
@@ -202,10 +202,18 @@
break;
case AAUDIO_STREAM_STATE_STARTED:
{
- // Sleep until the readCounter catches up and we only have
- // the getBufferSize() frames of data sitting in the buffer.
- int64_t nextReadPosition = mAudioEndpoint->getDataWriteCounter() - getBufferSize();
- wakeTime = mClockModel.convertPositionToTime(nextReadPosition);
+ // Calculate when there will be room available to write to the buffer.
+ // If the appBufferSize is smaller than the endpointBufferSize then
+ // we will have room to write data beyond the appBufferSize.
+ // That is a technique used to reduce glitches without adding latency.
+ const int32_t appBufferSize = getBufferSize();
+ // The endpoint buffer size is set to the maximum that can be written.
+ // If we use it then we must carve out some room to write data when we wake up.
+ const int32_t endBufferSize = mAudioEndpoint->getBufferSizeInFrames()
+ - getFramesPerBurst();
+ const int32_t bestBufferSize = std::min(appBufferSize, endBufferSize);
+ int64_t targetReadPosition = mAudioEndpoint->getDataWriteCounter() - bestBufferSize;
+ wakeTime = mClockModel.convertPositionToTime(targetReadPosition);
}
break;
default:
diff --git a/media/libaaudio/src/flowgraph/ChannelCountConverter.cpp b/media/libaaudio/src/flowgraph/ChannelCountConverter.cpp
index 351def2..dc80427 100644
--- a/media/libaaudio/src/flowgraph/ChannelCountConverter.cpp
+++ b/media/libaaudio/src/flowgraph/ChannelCountConverter.cpp
@@ -18,7 +18,7 @@
#include "FlowGraphNode.h"
#include "ChannelCountConverter.h"
-using namespace flowgraph;
+using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
ChannelCountConverter::ChannelCountConverter(
int32_t inputChannelCount,
diff --git a/media/libaaudio/src/flowgraph/ChannelCountConverter.h b/media/libaaudio/src/flowgraph/ChannelCountConverter.h
index e4b6f4e..858f4d4 100644
--- a/media/libaaudio/src/flowgraph/ChannelCountConverter.h
+++ b/media/libaaudio/src/flowgraph/ChannelCountConverter.h
@@ -22,7 +22,7 @@
#include "FlowGraphNode.h"
-namespace flowgraph {
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
/**
* Change the number of number of channels without mixing.
@@ -47,6 +47,6 @@
FlowGraphPortFloatOutput output;
};
-} /* namespace flowgraph */
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
#endif //FLOWGRAPH_CHANNEL_COUNT_CONVERTER_H
diff --git a/media/libaaudio/src/flowgraph/ClipToRange.cpp b/media/libaaudio/src/flowgraph/ClipToRange.cpp
index d2f8a02..c6ad0b0 100644
--- a/media/libaaudio/src/flowgraph/ClipToRange.cpp
+++ b/media/libaaudio/src/flowgraph/ClipToRange.cpp
@@ -19,7 +19,7 @@
#include "FlowGraphNode.h"
#include "ClipToRange.h"
-using namespace flowgraph;
+using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
ClipToRange::ClipToRange(int32_t channelCount)
: FlowGraphFilter(channelCount) {
diff --git a/media/libaaudio/src/flowgraph/ClipToRange.h b/media/libaaudio/src/flowgraph/ClipToRange.h
index 22b7804..2fddeee 100644
--- a/media/libaaudio/src/flowgraph/ClipToRange.h
+++ b/media/libaaudio/src/flowgraph/ClipToRange.h
@@ -23,7 +23,7 @@
#include "FlowGraphNode.h"
-namespace flowgraph {
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
// This is 3 dB, (10^(3/20)), to match the maximum headroom in AudioTrack for float data.
// It is designed to allow occasional transient peaks.
@@ -63,6 +63,6 @@
float mMaximum = kDefaultMaxHeadroom;
};
-} /* namespace flowgraph */
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
#endif //FLOWGRAPH_CLIP_TO_RANGE_H
diff --git a/media/libaaudio/src/flowgraph/FlowGraphNode.cpp b/media/libaaudio/src/flowgraph/FlowGraphNode.cpp
index 4c76e77..012abe7 100644
--- a/media/libaaudio/src/flowgraph/FlowGraphNode.cpp
+++ b/media/libaaudio/src/flowgraph/FlowGraphNode.cpp
@@ -19,7 +19,7 @@
#include <sys/types.h>
#include "FlowGraphNode.h"
-using namespace flowgraph;
+using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
/***************************************************************************/
int32_t FlowGraphNode::pullData(int32_t numFrames, int64_t callCount) {
@@ -68,7 +68,7 @@
: FlowGraphPort(parent, samplesPerFrame)
, mFramesPerBuffer(framesPerBuffer)
, mBuffer(nullptr) {
- size_t numFloats = framesPerBuffer * getSamplesPerFrame();
+ size_t numFloats = static_cast<size_t>(framesPerBuffer) * getSamplesPerFrame();
mBuffer = std::make_unique<float[]>(numFloats);
}
diff --git a/media/libaaudio/src/flowgraph/FlowGraphNode.h b/media/libaaudio/src/flowgraph/FlowGraphNode.h
index 69c83dd..2884c08 100644
--- a/media/libaaudio/src/flowgraph/FlowGraphNode.h
+++ b/media/libaaudio/src/flowgraph/FlowGraphNode.h
@@ -38,13 +38,26 @@
// TODO Review use of raw pointers for connect(). Maybe use smart pointers but need to avoid
// run-time deallocation in audio thread.
-// Set this to 1 if using it inside the Android framework.
-// This code is kept here so that it can be moved easily between Oboe and AAudio.
-#ifndef FLOWGRAPH_ANDROID_INTERNAL
-#define FLOWGRAPH_ANDROID_INTERNAL 0
-#endif
+// Set flags FLOWGRAPH_ANDROID_INTERNAL and FLOWGRAPH_OUTER_NAMESPACE based on whether compiler
+// flag __ANDROID_NDK__ is defined. __ANDROID_NDK__ should be defined in oboe and not aaudio.
-namespace flowgraph {
+#ifndef FLOWGRAPH_ANDROID_INTERNAL
+#ifdef __ANDROID_NDK__
+#define FLOWGRAPH_ANDROID_INTERNAL 0
+#else
+#define FLOWGRAPH_ANDROID_INTERNAL 1
+#endif // __ANDROID_NDK__
+#endif // FLOWGRAPH_ANDROID_INTERNAL
+
+#ifndef FLOWGRAPH_OUTER_NAMESPACE
+#ifdef __ANDROID_NDK__
+#define FLOWGRAPH_OUTER_NAMESPACE oboe
+#else
+#define FLOWGRAPH_OUTER_NAMESPACE aaudio
+#endif // __ANDROID_NDK__
+#endif // FLOWGRAPH_OUTER_NAMESPACE
+
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
// Default block size that can be overridden when the FlowGraphPortFloat is created.
// If it is too small then we will have too much overhead from switching between nodes.
@@ -432,6 +445,6 @@
FlowGraphPortFloatOutput output;
};
-} /* namespace flowgraph */
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
#endif /* FLOWGRAPH_FLOW_GRAPH_NODE_H */
diff --git a/media/libaaudio/src/flowgraph/FlowgraphUtilities.h b/media/libaaudio/src/flowgraph/FlowgraphUtilities.h
index b750410..ce2bc82 100644
--- a/media/libaaudio/src/flowgraph/FlowgraphUtilities.h
+++ b/media/libaaudio/src/flowgraph/FlowgraphUtilities.h
@@ -19,7 +19,7 @@
#include <unistd.h>
-using namespace flowgraph;
+using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
class FlowgraphUtilities {
public:
diff --git a/media/libaaudio/src/flowgraph/ManyToMultiConverter.cpp b/media/libaaudio/src/flowgraph/ManyToMultiConverter.cpp
index 879685e..4f973bc 100644
--- a/media/libaaudio/src/flowgraph/ManyToMultiConverter.cpp
+++ b/media/libaaudio/src/flowgraph/ManyToMultiConverter.cpp
@@ -18,7 +18,7 @@
#include "ManyToMultiConverter.h"
-using namespace flowgraph;
+using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
ManyToMultiConverter::ManyToMultiConverter(int32_t channelCount)
: inputs(channelCount)
diff --git a/media/libaaudio/src/flowgraph/ManyToMultiConverter.h b/media/libaaudio/src/flowgraph/ManyToMultiConverter.h
index c7460ff..50644cf 100644
--- a/media/libaaudio/src/flowgraph/ManyToMultiConverter.h
+++ b/media/libaaudio/src/flowgraph/ManyToMultiConverter.h
@@ -23,7 +23,7 @@
#include "FlowGraphNode.h"
-namespace flowgraph {
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
/**
* Combine multiple mono inputs into one interleaved multi-channel output.
@@ -48,6 +48,6 @@
private:
};
-} /* namespace flowgraph */
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
#endif //FLOWGRAPH_MANY_TO_MULTI_CONVERTER_H
diff --git a/media/libaaudio/src/flowgraph/MonoBlend.cpp b/media/libaaudio/src/flowgraph/MonoBlend.cpp
index 62e2809..4fd75e1 100644
--- a/media/libaaudio/src/flowgraph/MonoBlend.cpp
+++ b/media/libaaudio/src/flowgraph/MonoBlend.cpp
@@ -18,7 +18,7 @@
#include "MonoBlend.h"
-using namespace flowgraph;
+using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
MonoBlend::MonoBlend(int32_t channelCount)
: FlowGraphFilter(channelCount)
@@ -43,4 +43,4 @@
}
return numFrames;
-}
\ No newline at end of file
+}
diff --git a/media/libaaudio/src/flowgraph/MonoBlend.h b/media/libaaudio/src/flowgraph/MonoBlend.h
index 7e3c35b..f8d44ff 100644
--- a/media/libaaudio/src/flowgraph/MonoBlend.h
+++ b/media/libaaudio/src/flowgraph/MonoBlend.h
@@ -22,7 +22,7 @@
#include "FlowGraphNode.h"
-namespace flowgraph {
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
/**
* Combine data between multiple channels so each channel is an average
@@ -43,6 +43,6 @@
const float mInvChannelCount;
};
-} /* namespace flowgraph */
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
#endif //FLOWGRAPH_MONO_BLEND
diff --git a/media/libaaudio/src/flowgraph/MonoToMultiConverter.cpp b/media/libaaudio/src/flowgraph/MonoToMultiConverter.cpp
index c8d60b9..33eed52 100644
--- a/media/libaaudio/src/flowgraph/MonoToMultiConverter.cpp
+++ b/media/libaaudio/src/flowgraph/MonoToMultiConverter.cpp
@@ -18,7 +18,7 @@
#include "FlowGraphNode.h"
#include "MonoToMultiConverter.h"
-using namespace flowgraph;
+using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
MonoToMultiConverter::MonoToMultiConverter(int32_t outputChannelCount)
: input(*this, 1)
diff --git a/media/libaaudio/src/flowgraph/MonoToMultiConverter.h b/media/libaaudio/src/flowgraph/MonoToMultiConverter.h
index 6e87ccb..762edb0 100644
--- a/media/libaaudio/src/flowgraph/MonoToMultiConverter.h
+++ b/media/libaaudio/src/flowgraph/MonoToMultiConverter.h
@@ -22,7 +22,7 @@
#include "FlowGraphNode.h"
-namespace flowgraph {
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
/**
* Convert a monophonic stream to a multi-channel interleaved stream
@@ -44,6 +44,6 @@
FlowGraphPortFloatOutput output;
};
-} /* namespace flowgraph */
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
#endif //FLOWGRAPH_MONO_TO_MULTI_CONVERTER_H
diff --git a/media/libaaudio/src/flowgraph/MultiToManyConverter.cpp b/media/libaaudio/src/flowgraph/MultiToManyConverter.cpp
index f074364..5cdf594 100644
--- a/media/libaaudio/src/flowgraph/MultiToManyConverter.cpp
+++ b/media/libaaudio/src/flowgraph/MultiToManyConverter.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 The Android Open Source Project
+ * 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.
@@ -18,7 +18,7 @@
#include "FlowGraphNode.h"
#include "MultiToManyConverter.h"
-using namespace flowgraph;
+using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
MultiToManyConverter::MultiToManyConverter(int32_t channelCount)
: outputs(channelCount)
@@ -45,4 +45,3 @@
return numFrames;
}
-
diff --git a/media/libaaudio/src/flowgraph/MultiToManyConverter.h b/media/libaaudio/src/flowgraph/MultiToManyConverter.h
index de31475..dee40a2 100644
--- a/media/libaaudio/src/flowgraph/MultiToManyConverter.h
+++ b/media/libaaudio/src/flowgraph/MultiToManyConverter.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 The Android Open Source Project
+ * 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.
@@ -22,7 +22,7 @@
#include "FlowGraphNode.h"
-namespace flowgraph {
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
/**
* Convert a multi-channel interleaved stream to multiple mono-channel
@@ -44,6 +44,6 @@
flowgraph::FlowGraphPortFloatInput input;
};
-} /* namespace flowgraph */
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
-#endif //FLOWGRAPH_MULTI_TO_MANY_CONVERTER_H
+#endif //FLOWGRAPH_MULTI_TO_MANY_CONVERTER_H
\ No newline at end of file
diff --git a/media/libaaudio/src/flowgraph/MultiToMonoConverter.cpp b/media/libaaudio/src/flowgraph/MultiToMonoConverter.cpp
index c745108..467f95e 100644
--- a/media/libaaudio/src/flowgraph/MultiToMonoConverter.cpp
+++ b/media/libaaudio/src/flowgraph/MultiToMonoConverter.cpp
@@ -18,7 +18,7 @@
#include "FlowGraphNode.h"
#include "MultiToMonoConverter.h"
-using namespace flowgraph;
+using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
MultiToMonoConverter::MultiToMonoConverter(int32_t inputChannelCount)
: input(*this, inputChannelCount)
diff --git a/media/libaaudio/src/flowgraph/MultiToMonoConverter.h b/media/libaaudio/src/flowgraph/MultiToMonoConverter.h
index 37c53bd..bf5b7b6 100644
--- a/media/libaaudio/src/flowgraph/MultiToMonoConverter.h
+++ b/media/libaaudio/src/flowgraph/MultiToMonoConverter.h
@@ -22,7 +22,7 @@
#include "FlowGraphNode.h"
-namespace flowgraph {
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
/**
* Convert a multi-channel interleaved stream to a monophonic stream
@@ -44,6 +44,6 @@
FlowGraphPortFloatOutput output;
};
-} /* namespace flowgraph */
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
#endif //FLOWGRAPH_MULTI_TO_MONO_CONVERTER_H
diff --git a/media/libaaudio/src/flowgraph/RampLinear.cpp b/media/libaaudio/src/flowgraph/RampLinear.cpp
index 905ae07..80ac72a 100644
--- a/media/libaaudio/src/flowgraph/RampLinear.cpp
+++ b/media/libaaudio/src/flowgraph/RampLinear.cpp
@@ -19,7 +19,7 @@
#include "FlowGraphNode.h"
#include "RampLinear.h"
-using namespace flowgraph;
+using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
RampLinear::RampLinear(int32_t channelCount)
: FlowGraphFilter(channelCount) {
diff --git a/media/libaaudio/src/flowgraph/RampLinear.h b/media/libaaudio/src/flowgraph/RampLinear.h
index f285704..3839d6e 100644
--- a/media/libaaudio/src/flowgraph/RampLinear.h
+++ b/media/libaaudio/src/flowgraph/RampLinear.h
@@ -23,7 +23,7 @@
#include "FlowGraphNode.h"
-namespace flowgraph {
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
/**
* When the target is modified then the output will ramp smoothly
@@ -91,6 +91,6 @@
float mLevelTo = 0.0f;
};
-} /* namespace flowgraph */
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
#endif //FLOWGRAPH_RAMP_LINEAR_H
diff --git a/media/libaaudio/src/flowgraph/SampleRateConverter.cpp b/media/libaaudio/src/flowgraph/SampleRateConverter.cpp
index 5c3ed1f..a15fcb8 100644
--- a/media/libaaudio/src/flowgraph/SampleRateConverter.cpp
+++ b/media/libaaudio/src/flowgraph/SampleRateConverter.cpp
@@ -16,10 +16,11 @@
#include "SampleRateConverter.h"
-using namespace flowgraph;
-using namespace resampler;
+using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
+using namespace RESAMPLER_OUTER_NAMESPACE::resampler;
-SampleRateConverter::SampleRateConverter(int32_t channelCount, MultiChannelResampler &resampler)
+SampleRateConverter::SampleRateConverter(int32_t channelCount,
+ MultiChannelResampler &resampler)
: FlowGraphFilter(channelCount)
, mResampler(resampler) {
setDataPulledAutomatically(false);
diff --git a/media/libaaudio/src/flowgraph/SampleRateConverter.h b/media/libaaudio/src/flowgraph/SampleRateConverter.h
index 57d76a4..f883e6c 100644
--- a/media/libaaudio/src/flowgraph/SampleRateConverter.h
+++ b/media/libaaudio/src/flowgraph/SampleRateConverter.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef OBOE_SAMPLE_RATE_CONVERTER_H
-#define OBOE_SAMPLE_RATE_CONVERTER_H
+#ifndef FLOWGRAPH_SAMPLE_RATE_CONVERTER_H
+#define FLOWGRAPH_SAMPLE_RATE_CONVERTER_H
#include <unistd.h>
#include <sys/types.h>
@@ -23,7 +23,7 @@
#include "FlowGraphNode.h"
#include "resampler/MultiChannelResampler.h"
-namespace flowgraph {
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
class SampleRateConverter : public FlowGraphFilter {
public:
@@ -58,6 +58,6 @@
};
-} /* namespace flowgraph */
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
-#endif //OBOE_SAMPLE_RATE_CONVERTER_H
+#endif //FLOWGRAPH_SAMPLE_RATE_CONVERTER_H
diff --git a/media/libaaudio/src/flowgraph/SinkFloat.cpp b/media/libaaudio/src/flowgraph/SinkFloat.cpp
index 0588848..940a66b 100644
--- a/media/libaaudio/src/flowgraph/SinkFloat.cpp
+++ b/media/libaaudio/src/flowgraph/SinkFloat.cpp
@@ -19,7 +19,7 @@
#include "FlowGraphNode.h"
#include "SinkFloat.h"
-using namespace flowgraph;
+using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
SinkFloat::SinkFloat(int32_t channelCount)
: FlowGraphSink(channelCount) {
diff --git a/media/libaaudio/src/flowgraph/SinkFloat.h b/media/libaaudio/src/flowgraph/SinkFloat.h
index c812373..3be3f5d 100644
--- a/media/libaaudio/src/flowgraph/SinkFloat.h
+++ b/media/libaaudio/src/flowgraph/SinkFloat.h
@@ -23,7 +23,7 @@
#include "FlowGraphNode.h"
-namespace flowgraph {
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
/**
* AudioSink that lets you read data as 32-bit floats.
@@ -40,6 +40,6 @@
}
};
-} /* namespace flowgraph */
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
#endif //FLOWGRAPH_SINK_FLOAT_H
diff --git a/media/libaaudio/src/flowgraph/SinkI16.cpp b/media/libaaudio/src/flowgraph/SinkI16.cpp
index da7fd6b..690431c 100644
--- a/media/libaaudio/src/flowgraph/SinkI16.cpp
+++ b/media/libaaudio/src/flowgraph/SinkI16.cpp
@@ -23,7 +23,7 @@
#include <audio_utils/primitives.h>
#endif
-using namespace flowgraph;
+using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
SinkI16::SinkI16(int32_t channelCount)
: FlowGraphSink(channelCount) {}
diff --git a/media/libaaudio/src/flowgraph/SinkI16.h b/media/libaaudio/src/flowgraph/SinkI16.h
index 1e1ce3a..bf124f5 100644
--- a/media/libaaudio/src/flowgraph/SinkI16.h
+++ b/media/libaaudio/src/flowgraph/SinkI16.h
@@ -22,7 +22,7 @@
#include "FlowGraphNode.h"
-namespace flowgraph {
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
/**
* AudioSink that lets you read data as 16-bit signed integers.
@@ -38,6 +38,6 @@
}
};
-} /* namespace flowgraph */
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
#endif //FLOWGRAPH_SINK_I16_H
diff --git a/media/libaaudio/src/flowgraph/SinkI24.cpp b/media/libaaudio/src/flowgraph/SinkI24.cpp
index a9fb5d2..d4f68b6 100644
--- a/media/libaaudio/src/flowgraph/SinkI24.cpp
+++ b/media/libaaudio/src/flowgraph/SinkI24.cpp
@@ -25,7 +25,7 @@
#include <audio_utils/primitives.h>
#endif
-using namespace flowgraph;
+using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
SinkI24::SinkI24(int32_t channelCount)
: FlowGraphSink(channelCount) {}
diff --git a/media/libaaudio/src/flowgraph/SinkI24.h b/media/libaaudio/src/flowgraph/SinkI24.h
index 44078a9..6b4135e 100644
--- a/media/libaaudio/src/flowgraph/SinkI24.h
+++ b/media/libaaudio/src/flowgraph/SinkI24.h
@@ -22,7 +22,7 @@
#include "FlowGraphNode.h"
-namespace flowgraph {
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
/**
* AudioSink that lets you read data as packed 24-bit signed integers.
@@ -39,6 +39,6 @@
}
};
-} /* namespace flowgraph */
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
#endif //FLOWGRAPH_SINK_I24_H
diff --git a/media/libaaudio/src/flowgraph/SinkI32.cpp b/media/libaaudio/src/flowgraph/SinkI32.cpp
index 9fd4e96..b14b3d2 100644
--- a/media/libaaudio/src/flowgraph/SinkI32.cpp
+++ b/media/libaaudio/src/flowgraph/SinkI32.cpp
@@ -14,15 +14,15 @@
* limitations under the License.
*/
-#if FLOWGRAPH_ANDROID_INTERNAL
-#include <audio_utils/primitives.h>
-#endif
-
#include "FlowGraphNode.h"
#include "FlowgraphUtilities.h"
#include "SinkI32.h"
-using namespace flowgraph;
+#if FLOWGRAPH_ANDROID_INTERNAL
+#include <audio_utils/primitives.h>
+#endif
+
+using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
SinkI32::SinkI32(int32_t channelCount)
: FlowGraphSink(channelCount) {}
diff --git a/media/libaaudio/src/flowgraph/SinkI32.h b/media/libaaudio/src/flowgraph/SinkI32.h
index 7456d5f..35507ea 100644
--- a/media/libaaudio/src/flowgraph/SinkI32.h
+++ b/media/libaaudio/src/flowgraph/SinkI32.h
@@ -21,7 +21,7 @@
#include "FlowGraphNode.h"
-namespace flowgraph {
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
class SinkI32 : public FlowGraphSink {
public:
@@ -35,6 +35,6 @@
}
};
-} /* namespace flowgraph */
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
#endif //FLOWGRAPH_SINK_I32_H
diff --git a/media/libaaudio/src/flowgraph/SourceFloat.cpp b/media/libaaudio/src/flowgraph/SourceFloat.cpp
index 1b3daf1..a0c8827 100644
--- a/media/libaaudio/src/flowgraph/SourceFloat.cpp
+++ b/media/libaaudio/src/flowgraph/SourceFloat.cpp
@@ -19,7 +19,7 @@
#include "FlowGraphNode.h"
#include "SourceFloat.h"
-using namespace flowgraph;
+using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
SourceFloat::SourceFloat(int32_t channelCount)
: FlowGraphSourceBuffered(channelCount) {
diff --git a/media/libaaudio/src/flowgraph/SourceFloat.h b/media/libaaudio/src/flowgraph/SourceFloat.h
index 4719669..78053e5 100644
--- a/media/libaaudio/src/flowgraph/SourceFloat.h
+++ b/media/libaaudio/src/flowgraph/SourceFloat.h
@@ -22,7 +22,7 @@
#include "FlowGraphNode.h"
-namespace flowgraph {
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
/**
* AudioSource that reads a block of pre-defined float data.
@@ -39,6 +39,6 @@
}
};
-} /* namespace flowgraph */
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
#endif //FLOWGRAPH_SOURCE_FLOAT_H
diff --git a/media/libaaudio/src/flowgraph/SourceI16.cpp b/media/libaaudio/src/flowgraph/SourceI16.cpp
index 8813023..16cd2b3 100644
--- a/media/libaaudio/src/flowgraph/SourceI16.cpp
+++ b/media/libaaudio/src/flowgraph/SourceI16.cpp
@@ -24,7 +24,7 @@
#include <audio_utils/primitives.h>
#endif
-using namespace flowgraph;
+using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
SourceI16::SourceI16(int32_t channelCount)
: FlowGraphSourceBuffered(channelCount) {
diff --git a/media/libaaudio/src/flowgraph/SourceI16.h b/media/libaaudio/src/flowgraph/SourceI16.h
index fe440b2..923890c 100644
--- a/media/libaaudio/src/flowgraph/SourceI16.h
+++ b/media/libaaudio/src/flowgraph/SourceI16.h
@@ -22,7 +22,7 @@
#include "FlowGraphNode.h"
-namespace flowgraph {
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
/**
* AudioSource that reads a block of pre-defined 16-bit integer data.
*/
@@ -37,6 +37,6 @@
}
};
-} /* namespace flowgraph */
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
#endif //FLOWGRAPH_SOURCE_I16_H
diff --git a/media/libaaudio/src/flowgraph/SourceI24.cpp b/media/libaaudio/src/flowgraph/SourceI24.cpp
index 1975878..d54b958 100644
--- a/media/libaaudio/src/flowgraph/SourceI24.cpp
+++ b/media/libaaudio/src/flowgraph/SourceI24.cpp
@@ -17,14 +17,14 @@
#include <algorithm>
#include <unistd.h>
+#include "FlowGraphNode.h"
+#include "SourceI24.h"
+
#if FLOWGRAPH_ANDROID_INTERNAL
#include <audio_utils/primitives.h>
#endif
-#include "FlowGraphNode.h"
-#include "SourceI24.h"
-
-using namespace flowgraph;
+using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
constexpr int kBytesPerI24Packed = 3;
diff --git a/media/libaaudio/src/flowgraph/SourceI24.h b/media/libaaudio/src/flowgraph/SourceI24.h
index 3779534..fb66d4a 100644
--- a/media/libaaudio/src/flowgraph/SourceI24.h
+++ b/media/libaaudio/src/flowgraph/SourceI24.h
@@ -22,7 +22,7 @@
#include "FlowGraphNode.h"
-namespace flowgraph {
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
/**
* AudioSource that reads a block of pre-defined 24-bit packed integer data.
@@ -38,6 +38,6 @@
}
};
-} /* namespace flowgraph */
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
#endif //FLOWGRAPH_SOURCE_I24_H
diff --git a/media/libaaudio/src/flowgraph/SourceI32.cpp b/media/libaaudio/src/flowgraph/SourceI32.cpp
index 4b2e8c4..b1c8f75 100644
--- a/media/libaaudio/src/flowgraph/SourceI32.cpp
+++ b/media/libaaudio/src/flowgraph/SourceI32.cpp
@@ -17,14 +17,14 @@
#include <algorithm>
#include <unistd.h>
+#include "FlowGraphNode.h"
+#include "SourceI32.h"
+
#if FLOWGRAPH_ANDROID_INTERNAL
#include <audio_utils/primitives.h>
#endif
-#include "FlowGraphNode.h"
-#include "SourceI32.h"
-
-using namespace flowgraph;
+using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
SourceI32::SourceI32(int32_t channelCount)
: FlowGraphSourceBuffered(channelCount) {
diff --git a/media/libaaudio/src/flowgraph/SourceI32.h b/media/libaaudio/src/flowgraph/SourceI32.h
index b4e0d7b..7109469 100644
--- a/media/libaaudio/src/flowgraph/SourceI32.h
+++ b/media/libaaudio/src/flowgraph/SourceI32.h
@@ -21,7 +21,7 @@
#include "FlowGraphNode.h"
-namespace flowgraph {
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
class SourceI32 : public FlowGraphSourceBuffered {
public:
@@ -37,6 +37,6 @@
static constexpr float kScale = 1.0 / (1UL << 31);
};
-} /* namespace flowgraph */
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
#endif //FLOWGRAPH_SOURCE_I32_H
diff --git a/media/libaaudio/src/flowgraph/resampler/HyperbolicCosineWindow.h b/media/libaaudio/src/flowgraph/resampler/HyperbolicCosineWindow.h
index f6479ae..76ec0e7 100644
--- a/media/libaaudio/src/flowgraph/resampler/HyperbolicCosineWindow.h
+++ b/media/libaaudio/src/flowgraph/resampler/HyperbolicCosineWindow.h
@@ -19,7 +19,9 @@
#include <math.h>
-namespace resampler {
+#include "ResamplerDefinitions.h"
+
+namespace RESAMPLER_OUTER_NAMESPACE::resampler {
/**
* Calculate a HyperbolicCosineWindow window centered at 0.
@@ -64,5 +66,6 @@
double mInverseCoshAlpha = 1.0;
};
-} // namespace resampler
+} /* namespace RESAMPLER_OUTER_NAMESPACE::resampler */
+
#endif //RESAMPLER_HYPERBOLIC_COSINE_WINDOW_H
diff --git a/media/libaaudio/src/flowgraph/resampler/IntegerRatio.cpp b/media/libaaudio/src/flowgraph/resampler/IntegerRatio.cpp
index 4bd75b3..39e9b24 100644
--- a/media/libaaudio/src/flowgraph/resampler/IntegerRatio.cpp
+++ b/media/libaaudio/src/flowgraph/resampler/IntegerRatio.cpp
@@ -16,7 +16,7 @@
#include "IntegerRatio.h"
-using namespace resampler;
+using namespace RESAMPLER_OUTER_NAMESPACE::resampler;
// Enough primes to cover the common sample rates.
static const int kPrimes[] = {
diff --git a/media/libaaudio/src/flowgraph/resampler/IntegerRatio.h b/media/libaaudio/src/flowgraph/resampler/IntegerRatio.h
index 8c044d8..a6b524c 100644
--- a/media/libaaudio/src/flowgraph/resampler/IntegerRatio.h
+++ b/media/libaaudio/src/flowgraph/resampler/IntegerRatio.h
@@ -14,12 +14,14 @@
* limitations under the License.
*/
-#ifndef OBOE_INTEGER_RATIO_H
-#define OBOE_INTEGER_RATIO_H
+#ifndef RESAMPLER_INTEGER_RATIO_H
+#define RESAMPLER_INTEGER_RATIO_H
#include <sys/types.h>
-namespace resampler {
+#include "ResamplerDefinitions.h"
+
+namespace RESAMPLER_OUTER_NAMESPACE::resampler {
/**
* Represent the ratio of two integers.
@@ -47,6 +49,6 @@
int32_t mDenominator;
};
-} // namespace resampler
+} /* namespace RESAMPLER_OUTER_NAMESPACE::resampler */
-#endif //OBOE_INTEGER_RATIO_H
+#endif //RESAMPLER_INTEGER_RATIO_H
diff --git a/media/libaaudio/src/flowgraph/resampler/KaiserWindow.h b/media/libaaudio/src/flowgraph/resampler/KaiserWindow.h
index 73dbc41..f99f9b4 100644
--- a/media/libaaudio/src/flowgraph/resampler/KaiserWindow.h
+++ b/media/libaaudio/src/flowgraph/resampler/KaiserWindow.h
@@ -19,7 +19,9 @@
#include <math.h>
-namespace resampler {
+#include "ResamplerDefinitions.h"
+
+namespace RESAMPLER_OUTER_NAMESPACE::resampler {
/**
* Calculate a Kaiser window centered at 0.
@@ -83,5 +85,6 @@
double mInverseBesselBeta = 1.0;
};
-} // namespace resampler
+} /* namespace RESAMPLER_OUTER_NAMESPACE::resampler */
+
#endif //RESAMPLER_KAISER_WINDOW_H
diff --git a/media/libaaudio/src/flowgraph/resampler/LinearResampler.cpp b/media/libaaudio/src/flowgraph/resampler/LinearResampler.cpp
index a7748c1..cb4932a 100644
--- a/media/libaaudio/src/flowgraph/resampler/LinearResampler.cpp
+++ b/media/libaaudio/src/flowgraph/resampler/LinearResampler.cpp
@@ -16,7 +16,7 @@
#include "LinearResampler.h"
-using namespace resampler;
+using namespace RESAMPLER_OUTER_NAMESPACE::resampler;
LinearResampler::LinearResampler(const MultiChannelResampler::Builder &builder)
: MultiChannelResampler(builder) {
diff --git a/media/libaaudio/src/flowgraph/resampler/LinearResampler.h b/media/libaaudio/src/flowgraph/resampler/LinearResampler.h
index 6bde81d..5434379 100644
--- a/media/libaaudio/src/flowgraph/resampler/LinearResampler.h
+++ b/media/libaaudio/src/flowgraph/resampler/LinearResampler.h
@@ -14,15 +14,17 @@
* limitations under the License.
*/
-#ifndef OBOE_LINEAR_RESAMPLER_H
-#define OBOE_LINEAR_RESAMPLER_H
+#ifndef RESAMPLER_LINEAR_RESAMPLER_H
+#define RESAMPLER_LINEAR_RESAMPLER_H
#include <memory>
#include <sys/types.h>
#include <unistd.h>
-#include "MultiChannelResampler.h"
-namespace resampler {
+#include "MultiChannelResampler.h"
+#include "ResamplerDefinitions.h"
+
+namespace RESAMPLER_OUTER_NAMESPACE::resampler {
/**
* Simple resampler that uses bi-linear interpolation.
@@ -40,5 +42,6 @@
std::unique_ptr<float[]> mCurrentFrame;
};
-} // namespace resampler
-#endif //OBOE_LINEAR_RESAMPLER_H
+} /* namespace RESAMPLER_OUTER_NAMESPACE::resampler */
+
+#endif //RESAMPLER_LINEAR_RESAMPLER_H
diff --git a/media/libaaudio/src/flowgraph/resampler/MultiChannelResampler.cpp b/media/libaaudio/src/flowgraph/resampler/MultiChannelResampler.cpp
index d630520..7193ff3 100644
--- a/media/libaaudio/src/flowgraph/resampler/MultiChannelResampler.cpp
+++ b/media/libaaudio/src/flowgraph/resampler/MultiChannelResampler.cpp
@@ -25,11 +25,12 @@
#include "SincResampler.h"
#include "SincResamplerStereo.h"
-using namespace resampler;
+using namespace RESAMPLER_OUTER_NAMESPACE::resampler;
MultiChannelResampler::MultiChannelResampler(const MultiChannelResampler::Builder &builder)
: mNumTaps(builder.getNumTaps())
- , mX(builder.getChannelCount() * builder.getNumTaps() * 2)
+ , mX(static_cast<size_t>(builder.getChannelCount())
+ * static_cast<size_t>(builder.getNumTaps()) * 2)
, mSingleFrame(builder.getChannelCount())
, mChannelCount(builder.getChannelCount())
{
@@ -110,7 +111,7 @@
if (--mCursor < 0) {
mCursor = getNumTaps() - 1;
}
- float *dest = &mX[mCursor * getChannelCount()];
+ float *dest = &mX[static_cast<size_t>(mCursor) * static_cast<size_t>(getChannelCount())];
int offset = getNumTaps() * getChannelCount();
for (int channel = 0; channel < getChannelCount(); channel++) {
// Write twice so we avoid having to wrap when reading.
@@ -130,7 +131,7 @@
int32_t numRows,
double phaseIncrement,
float normalizedCutoff) {
- mCoefficients.resize(getNumTaps() * numRows);
+ mCoefficients.resize(static_cast<size_t>(getNumTaps()) * static_cast<size_t>(numRows));
int coefficientIndex = 0;
double phase = 0.0; // ranges from 0.0 to 1.0, fraction between samples
// Stretch the sinc function for low pass filtering.
@@ -150,7 +151,7 @@
#if MCR_USE_KAISER
float window = mKaiserWindow(tapPhase * numTapsHalfInverse);
#else
- float window = mCoshWindow(tapPhase * numTapsHalfInverse);
+ float window = mCoshWindow(static_cast<double>(tapPhase) * numTapsHalfInverse);
#endif
float coefficient = sinc(radians * cutoffScaler) * window;
mCoefficients.at(coefficientIndex++) = coefficient;
diff --git a/media/libaaudio/src/flowgraph/resampler/MultiChannelResampler.h b/media/libaaudio/src/flowgraph/resampler/MultiChannelResampler.h
index da79cad..717f3fd 100644
--- a/media/libaaudio/src/flowgraph/resampler/MultiChannelResampler.h
+++ b/media/libaaudio/src/flowgraph/resampler/MultiChannelResampler.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef OBOE_MULTICHANNEL_RESAMPLER_H
-#define OBOE_MULTICHANNEL_RESAMPLER_H
+#ifndef RESAMPLER_MULTICHANNEL_RESAMPLER_H
+#define RESAMPLER_MULTICHANNEL_RESAMPLER_H
#include <memory>
#include <vector>
@@ -34,7 +34,9 @@
#include "HyperbolicCosineWindow.h"
#endif
-namespace resampler {
+#include "ResamplerDefinitions.h"
+
+namespace RESAMPLER_OUTER_NAMESPACE::resampler {
class MultiChannelResampler {
@@ -267,5 +269,6 @@
const int mChannelCount;
};
-} // namespace resampler
-#endif //OBOE_MULTICHANNEL_RESAMPLER_H
+} /* namespace RESAMPLER_OUTER_NAMESPACE::resampler */
+
+#endif //RESAMPLER_MULTICHANNEL_RESAMPLER_H
diff --git a/media/libaaudio/src/flowgraph/resampler/PolyphaseResampler.cpp b/media/libaaudio/src/flowgraph/resampler/PolyphaseResampler.cpp
index aa4ffd9..e47ee8e 100644
--- a/media/libaaudio/src/flowgraph/resampler/PolyphaseResampler.cpp
+++ b/media/libaaudio/src/flowgraph/resampler/PolyphaseResampler.cpp
@@ -19,7 +19,7 @@
#include "IntegerRatio.h"
#include "PolyphaseResampler.h"
-using namespace resampler;
+using namespace RESAMPLER_OUTER_NAMESPACE::resampler;
PolyphaseResampler::PolyphaseResampler(const MultiChannelResampler::Builder &builder)
: MultiChannelResampler(builder)
@@ -42,7 +42,7 @@
// Multiply input times windowed sinc function.
float *coefficients = &mCoefficients[mCoefficientCursor];
- float *xFrame = &mX[mCursor * getChannelCount()];
+ float *xFrame = &mX[static_cast<size_t>(mCursor) * static_cast<size_t>(getChannelCount())];
for (int i = 0; i < mNumTaps; i++) {
float coefficient = *coefficients++;
for (int channel = 0; channel < getChannelCount(); channel++) {
diff --git a/media/libaaudio/src/flowgraph/resampler/PolyphaseResampler.h b/media/libaaudio/src/flowgraph/resampler/PolyphaseResampler.h
index 1aeb680..3642fce 100644
--- a/media/libaaudio/src/flowgraph/resampler/PolyphaseResampler.h
+++ b/media/libaaudio/src/flowgraph/resampler/PolyphaseResampler.h
@@ -14,16 +14,18 @@
* limitations under the License.
*/
-#ifndef OBOE_POLYPHASE_RESAMPLER_H
-#define OBOE_POLYPHASE_RESAMPLER_H
+#ifndef RESAMPLER_POLYPHASE_RESAMPLER_H
+#define RESAMPLER_POLYPHASE_RESAMPLER_H
#include <memory>
#include <vector>
#include <sys/types.h>
#include <unistd.h>
-#include "MultiChannelResampler.h"
-namespace resampler {
+#include "MultiChannelResampler.h"
+#include "ResamplerDefinitions.h"
+
+namespace RESAMPLER_OUTER_NAMESPACE::resampler {
/**
* Resampler that is optimized for a reduced ratio of sample rates.
* All of the coefficients for each possible phase value are pre-calculated.
@@ -46,6 +48,6 @@
};
-} // namespace resampler
+} /* namespace RESAMPLER_OUTER_NAMESPACE::resampler */
-#endif //OBOE_POLYPHASE_RESAMPLER_H
+#endif //RESAMPLER_POLYPHASE_RESAMPLER_H
diff --git a/media/libaaudio/src/flowgraph/resampler/PolyphaseResamplerMono.cpp b/media/libaaudio/src/flowgraph/resampler/PolyphaseResamplerMono.cpp
index c0e29b7..fdaf13e 100644
--- a/media/libaaudio/src/flowgraph/resampler/PolyphaseResamplerMono.cpp
+++ b/media/libaaudio/src/flowgraph/resampler/PolyphaseResamplerMono.cpp
@@ -17,7 +17,7 @@
#include <cassert>
#include "PolyphaseResamplerMono.h"
-using namespace resampler;
+using namespace RESAMPLER_OUTER_NAMESPACE::resampler;
#define MONO 1
diff --git a/media/libaaudio/src/flowgraph/resampler/PolyphaseResamplerMono.h b/media/libaaudio/src/flowgraph/resampler/PolyphaseResamplerMono.h
index 0a691a3..fe020b5 100644
--- a/media/libaaudio/src/flowgraph/resampler/PolyphaseResamplerMono.h
+++ b/media/libaaudio/src/flowgraph/resampler/PolyphaseResamplerMono.h
@@ -14,14 +14,16 @@
* limitations under the License.
*/
-#ifndef OBOE_POLYPHASE_RESAMPLER_MONO_H
-#define OBOE_POLYPHASE_RESAMPLER_MONO_H
+#ifndef RESAMPLER_POLYPHASE_RESAMPLER_MONO_H
+#define RESAMPLER_POLYPHASE_RESAMPLER_MONO_H
#include <sys/types.h>
#include <unistd.h>
-#include "PolyphaseResampler.h"
-namespace resampler {
+#include "PolyphaseResampler.h"
+#include "ResamplerDefinitions.h"
+
+namespace RESAMPLER_OUTER_NAMESPACE::resampler {
class PolyphaseResamplerMono : public PolyphaseResampler {
public:
@@ -34,6 +36,6 @@
void readFrame(float *frame) override;
};
-} // namespace resampler
+} /* namespace RESAMPLER_OUTER_NAMESPACE::resampler */
-#endif //OBOE_POLYPHASE_RESAMPLER_MONO_H
+#endif //RESAMPLER_POLYPHASE_RESAMPLER_MONO_H
diff --git a/media/libaaudio/src/flowgraph/resampler/PolyphaseResamplerStereo.cpp b/media/libaaudio/src/flowgraph/resampler/PolyphaseResamplerStereo.cpp
index e4bef74..b381851 100644
--- a/media/libaaudio/src/flowgraph/resampler/PolyphaseResamplerStereo.cpp
+++ b/media/libaaudio/src/flowgraph/resampler/PolyphaseResamplerStereo.cpp
@@ -17,7 +17,7 @@
#include <cassert>
#include "PolyphaseResamplerStereo.h"
-using namespace resampler;
+using namespace RESAMPLER_OUTER_NAMESPACE::resampler;
#define STEREO 2
diff --git a/media/libaaudio/src/flowgraph/resampler/PolyphaseResamplerStereo.h b/media/libaaudio/src/flowgraph/resampler/PolyphaseResamplerStereo.h
index e608483..ee4caba 100644
--- a/media/libaaudio/src/flowgraph/resampler/PolyphaseResamplerStereo.h
+++ b/media/libaaudio/src/flowgraph/resampler/PolyphaseResamplerStereo.h
@@ -14,14 +14,16 @@
* limitations under the License.
*/
-#ifndef OBOE_POLYPHASE_RESAMPLER_STEREO_H
-#define OBOE_POLYPHASE_RESAMPLER_STEREO_H
+#ifndef RESAMPLER_POLYPHASE_RESAMPLER_STEREO_H
+#define RESAMPLER_POLYPHASE_RESAMPLER_STEREO_H
#include <sys/types.h>
#include <unistd.h>
-#include "PolyphaseResampler.h"
-namespace resampler {
+#include "PolyphaseResampler.h"
+#include "ResamplerDefinitions.h"
+
+namespace RESAMPLER_OUTER_NAMESPACE::resampler {
class PolyphaseResamplerStereo : public PolyphaseResampler {
public:
@@ -34,6 +36,6 @@
void readFrame(float *frame) override;
};
-} // namespace resampler
+} /* namespace RESAMPLER_OUTER_NAMESPACE::resampler */
-#endif //OBOE_POLYPHASE_RESAMPLER_STEREO_H
+#endif //RESAMPLER_POLYPHASE_RESAMPLER_STEREO_H
diff --git a/media/libaaudio/src/flowgraph/resampler/README.md b/media/libaaudio/src/flowgraph/resampler/README.md
index 05d8a89..ea319c7 100644
--- a/media/libaaudio/src/flowgraph/resampler/README.md
+++ b/media/libaaudio/src/flowgraph/resampler/README.md
@@ -5,6 +5,17 @@
The converter is based on a sinc function that has been windowed by a hyperbolic cosine.
We found this had fewer artifacts than the more traditional Kaiser window.
+## Building the Resampler
+
+It is part of [Oboe](https://github.com/google/oboe) but has no dependencies on Oboe.
+So the contents of this folder can be used outside of Oboe.
+
+To build it for use outside of Oboe:
+
+1. Copy the "resampler" folder to a folder in your project that is in the include path.
+2. Add all of the \*.cpp files in the resampler folder to your project IDE or Makefile.
+3. In ResamplerDefinitions.h, define RESAMPLER_OUTER_NAMESPACE with your own project name. Alternatively, use -DRESAMPLER_OUTER_NAMESPACE=mynamespace when compiling to avoid modifying the resampler code.
+
## Creating a Resampler
Include the [main header](MultiChannelResampler.h) for the resampler.
@@ -88,4 +99,3 @@
When you are done, you should delete the Resampler to avoid a memory leak.
delete resampler;
-
diff --git a/media/libaaudio/src/flowgraph/resampler/ResamplerDefinitions.h b/media/libaaudio/src/flowgraph/resampler/ResamplerDefinitions.h
new file mode 100644
index 0000000..c6791ec
--- /dev/null
+++ b/media/libaaudio/src/flowgraph/resampler/ResamplerDefinitions.h
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+// Set flag RESAMPLER_OUTER_NAMESPACE based on whether compiler flag
+// __ANDROID_NDK__ is defined. __ANDROID_NDK__ should be defined in oboe
+// but not in android.
+
+#ifndef RESAMPLER_OUTER_NAMESPACE
+#ifdef __ANDROID_NDK__
+#define RESAMPLER_OUTER_NAMESPACE oboe
+#else
+#define RESAMPLER_OUTER_NAMESPACE aaudio
+#endif // __ANDROID_NDK__
+#endif // RESAMPLER_OUTER_NAMESPACE
diff --git a/media/libaaudio/src/flowgraph/resampler/SincResampler.cpp b/media/libaaudio/src/flowgraph/resampler/SincResampler.cpp
index 5e8a9e0..42d0ca2 100644
--- a/media/libaaudio/src/flowgraph/resampler/SincResampler.cpp
+++ b/media/libaaudio/src/flowgraph/resampler/SincResampler.cpp
@@ -18,7 +18,7 @@
#include <math.h>
#include "SincResampler.h"
-using namespace resampler;
+using namespace RESAMPLER_OUTER_NAMESPACE::resampler;
SincResampler::SincResampler(const MultiChannelResampler::Builder &builder)
: MultiChannelResampler(builder)
@@ -52,10 +52,12 @@
index2 -= mNumRows;
}
- float *coefficients1 = &mCoefficients[index1 * getNumTaps()];
- float *coefficients2 = &mCoefficients[index2 * getNumTaps()];
+ float *coefficients1 = &mCoefficients[static_cast<size_t>(index1)
+ * static_cast<size_t>(getNumTaps())];
+ float *coefficients2 = &mCoefficients[static_cast<size_t>(index2)
+ * static_cast<size_t>(getNumTaps())];
- float *xFrame = &mX[mCursor * getChannelCount()];
+ float *xFrame = &mX[static_cast<size_t>(mCursor) * static_cast<size_t>(getChannelCount())];
for (int i = 0; i < mNumTaps; i++) {
float coefficient1 = *coefficients1++;
float coefficient2 = *coefficients2++;
diff --git a/media/libaaudio/src/flowgraph/resampler/SincResampler.h b/media/libaaudio/src/flowgraph/resampler/SincResampler.h
index b235188..05ff092 100644
--- a/media/libaaudio/src/flowgraph/resampler/SincResampler.h
+++ b/media/libaaudio/src/flowgraph/resampler/SincResampler.h
@@ -14,15 +14,17 @@
* limitations under the License.
*/
-#ifndef OBOE_SINC_RESAMPLER_H
-#define OBOE_SINC_RESAMPLER_H
+#ifndef RESAMPLER_SINC_RESAMPLER_H
+#define RESAMPLER_SINC_RESAMPLER_H
#include <memory>
#include <sys/types.h>
#include <unistd.h>
-#include "MultiChannelResampler.h"
-namespace resampler {
+#include "MultiChannelResampler.h"
+#include "ResamplerDefinitions.h"
+
+namespace RESAMPLER_OUTER_NAMESPACE::resampler {
/**
* Resampler that can interpolate between coefficients.
@@ -43,5 +45,6 @@
double mPhaseScaler = 1.0;
};
-} // namespace resampler
-#endif //OBOE_SINC_RESAMPLER_H
+} /* namespace RESAMPLER_OUTER_NAMESPACE::resampler */
+
+#endif //RESAMPLER_SINC_RESAMPLER_H
diff --git a/media/libaaudio/src/flowgraph/resampler/SincResamplerStereo.cpp b/media/libaaudio/src/flowgraph/resampler/SincResamplerStereo.cpp
index ce00302..432137e 100644
--- a/media/libaaudio/src/flowgraph/resampler/SincResamplerStereo.cpp
+++ b/media/libaaudio/src/flowgraph/resampler/SincResamplerStereo.cpp
@@ -19,7 +19,7 @@
#include "SincResamplerStereo.h"
-using namespace resampler;
+using namespace RESAMPLER_OUTER_NAMESPACE::resampler;
#define STEREO 2
@@ -54,13 +54,15 @@
// Determine indices into coefficients table.
double tablePhase = getIntegerPhase() * mPhaseScaler;
int index1 = static_cast<int>(floor(tablePhase));
- float *coefficients1 = &mCoefficients[index1 * getNumTaps()];
+ float *coefficients1 = &mCoefficients[static_cast<size_t>(index1)
+ * static_cast<size_t>(getNumTaps())];
int index2 = (index1 + 1);
if (index2 >= mNumRows) { // no guard row needed because we wrap the indices
index2 = 0;
}
- float *coefficients2 = &mCoefficients[index2 * getNumTaps()];
- float *xFrame = &mX[mCursor * getChannelCount()];
+ float *coefficients2 = &mCoefficients[static_cast<size_t>(index2)
+ * static_cast<size_t>(getNumTaps())];
+ float *xFrame = &mX[static_cast<size_t>(mCursor) * static_cast<size_t>(getChannelCount())];
for (int i = 0; i < mNumTaps; i++) {
float coefficient1 = *coefficients1++;
float coefficient2 = *coefficients2++;
diff --git a/media/libaaudio/src/flowgraph/resampler/SincResamplerStereo.h b/media/libaaudio/src/flowgraph/resampler/SincResamplerStereo.h
index 7d49ec7..d5576d1 100644
--- a/media/libaaudio/src/flowgraph/resampler/SincResamplerStereo.h
+++ b/media/libaaudio/src/flowgraph/resampler/SincResamplerStereo.h
@@ -14,14 +14,16 @@
* limitations under the License.
*/
-#ifndef OBOE_SINC_RESAMPLER_STEREO_H
-#define OBOE_SINC_RESAMPLER_STEREO_H
+#ifndef RESAMPLER_SINC_RESAMPLER_STEREO_H
+#define RESAMPLER_SINC_RESAMPLER_STEREO_H
#include <sys/types.h>
#include <unistd.h>
-#include "SincResampler.h"
-namespace resampler {
+#include "SincResampler.h"
+#include "ResamplerDefinitions.h"
+
+namespace RESAMPLER_OUTER_NAMESPACE::resampler {
class SincResamplerStereo : public SincResampler {
public:
@@ -35,5 +37,6 @@
};
-} // namespace resampler
-#endif //OBOE_SINC_RESAMPLER_STEREO_H
+} /* namespace RESAMPLER_OUTER_NAMESPACE::resampler */
+
+#endif //RESAMPLER_SINC_RESAMPLER_STEREO_H
diff --git a/media/libaaudio/src/utility/AAudioUtilities.cpp b/media/libaaudio/src/utility/AAudioUtilities.cpp
index 4b42203..872faca 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.cpp
+++ b/media/libaaudio/src/utility/AAudioUtilities.cpp
@@ -562,7 +562,9 @@
int32_t AAudioProperty_getMinimumSleepMicros() {
const int32_t minMicros = 1; // arbitrary
// Higher values can increase latency for moderate workloads.
- const int32_t defaultMicros = 1; // arbitrary
+ // Short values can cause the CPU to short cycle if there is a bug in
+ // calculating the wakeup times.
+ const int32_t defaultMicros = 100; // arbitrary
const int32_t maxMicros = 200; // arbitrary
int32_t prop = property_get_int32(AAUDIO_PROP_MINIMUM_SLEEP_USEC, defaultMicros);
if (prop < minMicros) {
diff --git a/media/libaaudio/tests/test_flowgraph.cpp b/media/libaaudio/tests/test_flowgraph.cpp
index e322791..913feb0 100644
--- a/media/libaaudio/tests/test_flowgraph.cpp
+++ b/media/libaaudio/tests/test_flowgraph.cpp
@@ -33,7 +33,7 @@
#include "flowgraph/SourceI16.h"
#include "flowgraph/SourceI24.h"
-using namespace flowgraph;
+using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
constexpr int kBytesPerI24Packed = 3;
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index e890e97..69a9c68 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -345,7 +345,7 @@
"aidl/android/media/TrackSecondaryOutputInfo.aidl",
],
imports: [
- "android.media.audio.common.types",
+ "android.media.audio.common.types-V1",
"framework-permission-aidl",
],
backend: {
@@ -389,7 +389,7 @@
"aidl/android/media/SpatializerHeadTrackingMode.aidl",
],
imports: [
- "android.media.audio.common.types",
+ "android.media.audio.common.types-V1",
"audioclient-types-aidl",
],
backend: {
@@ -432,7 +432,7 @@
"aidl/android/media/IAudioTrackCallback.aidl",
],
imports: [
- "android.media.audio.common.types",
+ "android.media.audio.common.types-V1",
"audioclient-types-aidl",
"av-types-aidl",
"effect-aidl",
@@ -469,7 +469,7 @@
"aidl/android/media/IAudioPolicyServiceClient.aidl",
],
imports: [
- "android.media.audio.common.types",
+ "android.media.audio.common.types-V1",
"audioclient-types-aidl",
"audiopolicy-types-aidl",
"capture_state_listener-aidl",
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index 0871365..15203d6 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -1331,6 +1331,7 @@
const sp<IAudioRecordCallback> callback = mCallback.promote();
if (!callback) {
mCallback = nullptr;
+ mLock.unlock();
return NS_NEVER;
}
if (mAwaitBoost) {
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 9a7b9c1..de8c298 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -70,6 +70,7 @@
dynamic_policy_callback AudioSystem::gDynPolicyCallback = NULL;
record_config_callback AudioSystem::gRecordConfigCallback = NULL;
routing_callback AudioSystem::gRoutingCallback = NULL;
+vol_range_init_req_callback AudioSystem::gVolRangeInitReqCallback = NULL;
// Required to be held while calling into gSoundTriggerCaptureStateListener.
class CaptureStateListenerImpl;
@@ -781,6 +782,11 @@
gRoutingCallback = cb;
}
+/*static*/ void AudioSystem::setVolInitReqCallback(vol_range_init_req_callback cb) {
+ Mutex::Autolock _l(gLock);
+ gVolRangeInitReqCallback = cb;
+}
+
// client singleton for AudioPolicyService binder interface
// protected by gLockAPS
sp<IAudioPolicyService> AudioSystem::gAudioPolicyService;
@@ -826,6 +832,11 @@
return ap;
}
+void AudioSystem::clearAudioPolicyService() {
+ Mutex::Autolock _l(gLockAPS);
+ gAudioPolicyService.clear();
+}
+
// ---------------------------------------------------------------------------
void AudioSystem::onNewAudioModulesAvailable() {
@@ -1144,8 +1155,15 @@
legacy2aidl_audio_stream_type_t_AudioStreamType(stream));
int32_t indexMinAidl = VALUE_OR_RETURN_STATUS(convertIntegral<int32_t>(indexMin));
int32_t indexMaxAidl = VALUE_OR_RETURN_STATUS(convertIntegral<int32_t>(indexMax));
- return statusTFromBinderStatus(
+ status_t status = statusTFromBinderStatus(
aps->initStreamVolume(streamAidl, indexMinAidl, indexMaxAidl));
+ if (status == DEAD_OBJECT) {
+ // This is a critical operation since w/o proper stream volumes no audio
+ // will be heard. Make sure we recover from a failure in any case.
+ ALOGE("Received DEAD_OBJECT from APS, clearing the client");
+ clearAudioPolicyService();
+ }
+ return status;
}
status_t AudioSystem::setStreamVolumeIndex(audio_stream_type_t stream,
@@ -1406,10 +1424,7 @@
}
gAudioFlinger.clear();
}
- {
- Mutex::Autolock _l(gLockAPS);
- gAudioPolicyService.clear();
- }
+ clearAudioPolicyService();
}
status_t AudioSystem::setSupportedSystemUsages(const std::vector<audio_usage_t>& systemUsages) {
@@ -2574,6 +2589,19 @@
return Status::ok();
}
+Status AudioSystem::AudioPolicyServiceClient::onVolumeRangeInitRequest() {
+ vol_range_init_req_callback cb = NULL;
+ {
+ Mutex::Autolock _l(AudioSystem::gLock);
+ cb = gVolRangeInitReqCallback;
+ }
+
+ if (cb != NULL) {
+ cb();
+ }
+ return Status::ok();
+}
+
void AudioSystem::AudioPolicyServiceClient::binderDied(const wp<IBinder>& who __unused) {
{
Mutex::Autolock _l(mLock);
@@ -2584,10 +2612,7 @@
mAudioVolumeGroupCallback[i]->onServiceDied();
}
}
- {
- Mutex::Autolock _l(gLockAPS);
- AudioSystem::gAudioPolicyService.clear();
- }
+ AudioSystem::clearAudioPolicyService();
ALOGW("AudioPolicyService server died!");
}
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index bec6b10..36f8e10 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -2448,6 +2448,7 @@
sp<IAudioTrackCallback> callback = mCallback.promote();
if (!callback) {
mCallback = nullptr;
+ mLock.unlock();
return NS_NEVER;
}
if (mAwaitBoost) {
diff --git a/media/libaudioclient/ToneGenerator.cpp b/media/libaudioclient/ToneGenerator.cpp
index 9b43f3c..4662247 100644
--- a/media/libaudioclient/ToneGenerator.cpp
+++ b/media/libaudioclient/ToneGenerator.cpp
@@ -17,6 +17,7 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "ToneGenerator"
+#include <inttypes.h>
#include <utility>
#include <math.h>
@@ -1229,7 +1230,8 @@
sec = sec * 1000 + nsec / 1000000; // duration in milliseconds
mMaxSmp = (unsigned int)(((int64_t)sec * mSamplingRate) / 1000);
}
- ALOGV("stopTone() forcing mMaxSmp to %d, total for far %d", mMaxSmp, mTotalSmp);
+ ALOGV("stopTone() forcing mMaxSmp to %d, total for far %" PRIu64, mMaxSmp,
+ mTotalSmp);
} else {
mState = TONE_STOPPING;
}
@@ -1399,7 +1401,7 @@
mNextSegSmp = TONEGEN_INF; // forced to skip state machine management below
}
- if (mTotalSmp > mNextSegSmp) {
+ if (mTotalSmp > mNextSegSmp && mNextSegSmp != TONEGEN_INF) {
// Time to go to next sequence segment
ALOGV("End Segment, time: %d", (unsigned int)(systemTime()/1000000));
@@ -1483,8 +1485,11 @@
}
// Update next segment transition position. No harm to do it also for last segment as
- // mNextSegSmp won't be used any more
- mNextSegSmp += (mpToneDesc->segments[mCurSegment].duration * mSamplingRate) / 1000;
+ // mNextSegSmp won't be used any more.
+ // Handle 32 bit wraparound gracefully.
+ const uint64_t res = static_cast<uint64_t>(mNextSegSmp) +
+ (mpToneDesc->segments[mCurSegment].duration * mSamplingRate) / 1000;
+ mNextSegSmp = static_cast<uint32_t>(std::min<uint64_t>(TONEGEN_INF, res));
} else {
// Inside a segment keep tone ON or OFF
diff --git a/media/libaudioclient/aidl/android/media/IAudioPolicyServiceClient.aidl b/media/libaudioclient/aidl/android/media/IAudioPolicyServiceClient.aidl
index d93a59d..c0cdd96 100644
--- a/media/libaudioclient/aidl/android/media/IAudioPolicyServiceClient.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioPolicyServiceClient.aidl
@@ -46,4 +46,7 @@
AudioSource source);
/** Notifies a change of audio routing */
void onRoutingUpdated();
+ /** Notifies a request for volume index ranges to be reset after they were observed as invalid
+ */
+ void onVolumeRangeInitRequest();
}
diff --git a/media/libaudioclient/aidl/android/media/ISpatializer.aidl b/media/libaudioclient/aidl/android/media/ISpatializer.aidl
index b871238..a61ad58 100644
--- a/media/libaudioclient/aidl/android/media/ISpatializer.aidl
+++ b/media/libaudioclient/aidl/android/media/ISpatializer.aidl
@@ -57,8 +57,10 @@
boolean isHeadTrackingSupported();
/** Reports the list of supported head tracking modes (see SpatializerHeadTrackingMode.aidl).
- * The list can be empty if the spatializer implementation does not support head tracking or if
- * no head tracking sensor is registered (see setHeadSensor() and setScreenSensor()).
+ * The list always contains SpatializerHeadTrackingMode.DISABLED and can include other modes
+ * if the spatializer effect implementation supports head tracking.
+ * The result does not depend on currently connected sensors but reflects the capabilities
+ * when sensors are available.
*/
SpatializerHeadTrackingMode[] getSupportedHeadTrackingModes();
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 1cc22a0..360b83d 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -77,6 +77,7 @@
audio_patch_handle_t patchHandle,
audio_source_t source);
typedef void (*routing_callback)();
+typedef void (*vol_range_init_req_callback)();
class IAudioFlinger;
class String8;
@@ -154,6 +155,7 @@
static void setDynPolicyCallback(dynamic_policy_callback cb);
static void setRecordConfigCallback(record_config_callback);
static void setRoutingCallback(routing_callback cb);
+ static void setVolInitReqCallback(vol_range_init_req_callback cb);
// Sets the binder to use for accessing the AudioFlinger service. This enables the system server
// to grant specific isolated processes access to the audio system. Currently used only for the
@@ -348,6 +350,7 @@
static void clearAudioConfigCache();
static const sp<media::IAudioPolicyService> get_audio_policy_service();
+ static void clearAudioPolicyService();
// helpers for android.media.AudioManager.getProperty(), see description there for meaning
static uint32_t getPrimaryOutputSamplingRate();
@@ -736,6 +739,7 @@
int32_t patchHandle,
media::audio::common::AudioSource source) override;
binder::Status onRoutingUpdated();
+ binder::Status onVolumeRangeInitRequest();
private:
Mutex mLock;
@@ -763,6 +767,7 @@
static dynamic_policy_callback gDynPolicyCallback;
static record_config_callback gRecordConfigCallback;
static routing_callback gRoutingCallback;
+ static vol_range_init_req_callback gVolRangeInitReqCallback;
static size_t gInBuffSize;
// previous parameters for recording buffer size queries
diff --git a/media/libaudioclient/include/media/ToneGenerator.h b/media/libaudioclient/include/media/ToneGenerator.h
index 43c0100..d00dfd2 100644
--- a/media/libaudioclient/include/media/ToneGenerator.h
+++ b/media/libaudioclient/include/media/ToneGenerator.h
@@ -287,11 +287,10 @@
static const ToneDescriptor sToneDescriptors[];
bool mThreadCanCallJava;
- unsigned int mTotalSmp; // Total number of audio samples played (gives current time)
+ uint64_t mTotalSmp; // Total number of audio samples played (gives current time)
+ // Since these types are 32 bit, we may have issues with aborting on
+ // overflow now that we have integer overflow sanitization enabled globally.
unsigned int mNextSegSmp; // Position of next segment transition expressed in samples
- // NOTE: because mTotalSmp, mNextSegSmp are stored on 32 bit, current design will operate properly
- // only if tone duration is less than about 27 Hours(@44100Hz sampling rate). If this time is exceeded,
- // no crash will occur but tone sequence will show a glitch.
unsigned int mMaxSmp; // Maximum number of audio samples played (maximun tone duration)
int mDurationMs; // Maximum tone duration in ms
diff --git a/media/libaudiofoundation/AudioContainers.cpp b/media/libaudiofoundation/AudioContainers.cpp
index 553a319..0a8188f 100644
--- a/media/libaudiofoundation/AudioContainers.cpp
+++ b/media/libaudiofoundation/AudioContainers.cpp
@@ -70,6 +70,13 @@
return audioDeviceOutAllBleSet;
}
+const DeviceTypeSet& getAudioDeviceOutLeAudioUnicastSet() {
+ static const DeviceTypeSet audioDeviceOutLeAudioUnicastSet = DeviceTypeSet(
+ std::begin(AUDIO_DEVICE_OUT_BLE_UNICAST_ARRAY),
+ std::end(AUDIO_DEVICE_OUT_BLE_UNICAST_ARRAY));
+ return audioDeviceOutLeAudioUnicastSet;
+}
+
std::string deviceTypesToString(const DeviceTypeSet &deviceTypes) {
if (deviceTypes.empty()) {
return "Empty device types";
diff --git a/media/libaudiofoundation/include/media/AudioContainers.h b/media/libaudiofoundation/include/media/AudioContainers.h
index a9c7824..b6e6c84 100644
--- a/media/libaudiofoundation/include/media/AudioContainers.h
+++ b/media/libaudiofoundation/include/media/AudioContainers.h
@@ -41,6 +41,7 @@
const DeviceTypeSet& getAudioDeviceInAllSet();
const DeviceTypeSet& getAudioDeviceInAllUsbSet();
const DeviceTypeSet& getAudioDeviceOutAllBleSet();
+const DeviceTypeSet& getAudioDeviceOutLeAudioUnicastSet();
template<typename T>
static std::vector<T> Intersection(const std::set<T>& a, const std::set<T>& b) {
diff --git a/media/libheadtracking/SensorPoseProvider.cpp b/media/libheadtracking/SensorPoseProvider.cpp
index f3f9b77..4884ae4 100644
--- a/media/libheadtracking/SensorPoseProvider.cpp
+++ b/media/libheadtracking/SensorPoseProvider.cpp
@@ -158,7 +158,6 @@
enum DataFormat {
kUnknown,
kQuaternion,
- kRotationVectorsAndFlags,
kRotationVectorsAndDiscontinuityCount,
};
@@ -283,10 +282,6 @@
return DataFormat::kRotationVectorsAndDiscontinuityCount;
}
- if (sensor->getStringType() == "com.google.hardware.sensor.hid_dynamic.headtracker") {
- return DataFormat::kRotationVectorsAndFlags;
- }
-
return DataFormat::kUnknown;
}
@@ -332,21 +327,6 @@
return PoseEvent{Pose3f(quat), std::optional<Twist3f>(), false};
}
- case DataFormat::kRotationVectorsAndFlags: {
- // Custom sensor, assumed to contain:
- // 3 floats representing orientation as a rotation vector (in rad).
- // 3 floats representing angular velocity as a rotation vector (in rad/s).
- // 1 uint32_t of flags, where:
- // - LSb is '1' iff the given sample is the first one in a new frame of reference.
- // - The rest of the bits are reserved for future use.
- Eigen::Vector3f rotation = {event.data[0], event.data[1], event.data[2]};
- Eigen::Vector3f twist = {event.data[3], event.data[4], event.data[5]};
- Eigen::Quaternionf quat = rotationVectorToQuaternion(rotation);
- uint32_t flags = *reinterpret_cast<const uint32_t*>(&event.data[6]);
- return PoseEvent{Pose3f(quat), Twist3f(Eigen::Vector3f::Zero(), twist),
- (flags & (1 << 0)) != 0};
- }
-
case DataFormat::kRotationVectorsAndDiscontinuityCount: {
Eigen::Vector3f rotation = {event.head_tracker.rx, event.head_tracker.ry,
event.head_tracker.rz};
diff --git a/media/libmediahelper/Android.bp b/media/libmediahelper/Android.bp
index b9d795d..165a8ad 100644
--- a/media/libmediahelper/Android.bp
+++ b/media/libmediahelper/Android.bp
@@ -44,7 +44,10 @@
"-Wextra",
"-Wall",
],
- shared_libs: ["libutils", "liblog"],
+ shared_libs: [
+ "libutils",
+ "liblog",
+ ],
header_libs: [
"libmedia_helper_headers",
"libaudio_system_headers",
@@ -52,7 +55,7 @@
export_header_lib_headers: [
"libmedia_helper_headers",
],
- clang: true,
+
host_supported: true,
target: {
darwin: {
diff --git a/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp b/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
index 55b1ed7..b3f7f25 100644
--- a/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
+++ b/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
@@ -216,7 +216,8 @@
sp<AMessage> format = new AMessage;
status_t err = convertMetaDataToMessage(trackMeta, &format);
if (err != OK) {
- format = NULL;
+ ALOGE("getImageInternal: convertMetaDataToMessage() failed, unable to extract image");
+ return NULL;
}
uint32_t bitDepth = 8;
@@ -400,7 +401,8 @@
sp<AMessage> format = new AMessage;
status_t err = convertMetaDataToMessage(trackMeta, &format);
if (err != OK) {
- format = NULL;
+ ALOGE("getFrameInternal: convertMetaDataToMessage() failed, unable to extract frame");
+ return NULL;
}
Vector<AString> matchingCodecs;
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index e47e7ff..10baec4 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -253,6 +253,40 @@
],
},
}
+
+cc_library_shared {
+ name: "libstagefright_surface_utils",
+
+ srcs: [
+ "SurfaceUtils.cpp",
+ ],
+
+ shared_libs: [
+ "libgui",
+ "liblog",
+ "libui",
+ "libutils",
+ ],
+
+ export_include_dirs: [
+ "include",
+ ],
+
+ cflags: [
+ "-Wno-multichar",
+ "-Werror",
+ "-Wall",
+ ],
+
+ sanitize: {
+ cfi: true,
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ },
+}
+
cc_library {
name: "libstagefright",
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 95afa62..9607425 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -564,9 +564,11 @@
// Set the preview display. Skip this if mSurface is null because
// applications may already set a surface to the camera.
if (mSurface != NULL) {
- // This CHECK is good, since we just passed the lock/unlock
- // check earlier by calling mCamera->setParameters().
- CHECK_EQ((status_t)OK, mCamera->setPreviewTarget(mSurface));
+ // Surface may be set incorrectly or could already be used even if we just
+ // passed the lock/unlock check earlier by calling mCamera->setParameters().
+ if ((err = mCamera->setPreviewTarget(mSurface)) != OK) {
+ return err;
+ }
}
// Use buffer queue to receive video buffers from camera
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 2f3792e..5a27362 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -186,9 +186,12 @@
// XXX suppress until we get our representation right
static bool kEmitHistogram = false;
+static int64_t getId(IResourceManagerClient const * client) {
+ return (int64_t) client;
+}
static int64_t getId(const std::shared_ptr<IResourceManagerClient> &client) {
- return (int64_t) client.get();
+ return getId(client.get());
}
static bool isResourceError(status_t err) {
@@ -205,12 +208,20 @@
////////////////////////////////////////////////////////////////////////////////
struct ResourceManagerClient : public BnResourceManagerClient {
- explicit ResourceManagerClient(MediaCodec* codec) : mMediaCodec(codec) {}
+ explicit ResourceManagerClient(MediaCodec* codec, int32_t pid) :
+ mMediaCodec(codec), mPid(pid) {}
Status reclaimResource(bool* _aidl_return) override {
sp<MediaCodec> codec = mMediaCodec.promote();
if (codec == NULL) {
- // codec is already gone.
+ // Codec is already gone, so remove the resources as well
+ ::ndk::SpAIBinder binder(AServiceManager_getService("media.resource_manager"));
+ std::shared_ptr<IResourceManagerService> service =
+ IResourceManagerService::fromBinder(binder);
+ if (service == nullptr) {
+ ALOGW("MediaCodec::ResourceManagerClient unable to find ResourceManagerService");
+ }
+ service->removeClient(mPid, getId(this));
*_aidl_return = true;
return Status::ok();
}
@@ -247,6 +258,7 @@
private:
wp<MediaCodec> mMediaCodec;
+ int32_t mPid;
DISALLOW_EVIL_CONSTRUCTORS(ResourceManagerClient);
};
@@ -820,7 +832,7 @@
mGetCodecBase(getCodecBase),
mGetCodecInfo(getCodecInfo) {
mResourceManagerProxy = new ResourceManagerServiceProxy(pid, uid,
- ::ndk::SharedRefBase::make<ResourceManagerClient>(this));
+ ::ndk::SharedRefBase::make<ResourceManagerClient>(this, pid));
if (!mGetCodecBase) {
mGetCodecBase = [](const AString &name, const char *owner) {
return GetCodecBase(name, owner);
@@ -3053,8 +3065,9 @@
CHECK(msg->findInt32("err", &err));
CHECK(msg->findInt32("actionCode", &actionCode));
- ALOGE("Codec reported err %#x, actionCode %d, while in state %d/%s",
- err, actionCode, mState, stateString(mState).c_str());
+ ALOGE("Codec reported err %#x/%s, actionCode %d, while in state %d/%s",
+ err, StrMediaError(err).c_str(), actionCode,
+ mState, stateString(mState).c_str());
if (err == DEAD_OBJECT) {
mFlags |= kFlagSawMediaServerDie;
mFlags &= ~kFlagIsComponentAllocated;
diff --git a/media/libstagefright/foundation/Android.bp b/media/libstagefright/foundation/Android.bp
index 1b31392..ca17117 100644
--- a/media/libstagefright/foundation/Android.bp
+++ b/media/libstagefright/foundation/Android.bp
@@ -120,8 +120,6 @@
},
},
- clang: true,
-
sanitize: {
misc_undefined: [
"unsigned-integer-overflow",
@@ -172,7 +170,7 @@
shared_libs: [
"liblog",
- "libutils", // for sp<>
+ "libutils", // for sp<>
// actually invokes this, but called from folks who already load it
// "libmediandk",
],
@@ -200,8 +198,6 @@
"ColorUtils_fill.cpp",
],
- clang: true,
-
sanitize: {
misc_undefined: [
"unsigned-integer-overflow",
@@ -218,4 +214,3 @@
],
}
-
diff --git a/media/libstagefright/foundation/MetaDataBase.cpp b/media/libstagefright/foundation/MetaDataBase.cpp
index 980eb22..3370748 100644
--- a/media/libstagefright/foundation/MetaDataBase.cpp
+++ b/media/libstagefright/foundation/MetaDataBase.cpp
@@ -521,9 +521,64 @@
}
setData(key, type, blob.data(), size);
blob.release();
+ } else if (type == TYPE_C_STRING) {
+ // copy data directly from Parcel storage, then advance position
+ // NB: readInplace() bumps position, it is NOT idempotent.
+ const void *src = parcel.readInplace(size);
+ char *str = (char *) src;
+ if (src == nullptr || size == 0 || str[size-1] != '\0') {
+ char ccKey[5];
+ MakeFourCCString(key, ccKey);
+ if (src == nullptr) {
+ ALOGW("ignoring key '%s' string with no data (expected %d)", ccKey, size);
+ } else {
+ ALOGW("ignoring key '%s': unterminated string of %d bytes", ccKey, size);
+ }
+ } else {
+ setData(key, type, src, size);
+ }
} else {
// copy data directly from Parcel storage, then advance position
- setData(key, type, parcel.readInplace(size), size);
+ // verify that the received size is enough
+ uint32_t needed = 0;
+ switch (type) {
+ case TYPE_INT32:
+ needed = sizeof(int32_t);
+ break;
+ case TYPE_INT64:
+ needed = sizeof(int64_t);
+ break;
+ case TYPE_FLOAT:
+ needed = sizeof(float);
+ break;
+ case TYPE_POINTER:
+ // NB: this rejects passing between 32-bit and 64-bit space.
+ needed = sizeof(void*);
+ break;
+ case TYPE_RECT:
+ needed = sizeof(Rect);
+ break;
+ default:
+ // non-standard entities can be any size >= 0
+ needed = 0;
+ break;
+ }
+ const void *src = parcel.readInplace(size);
+ if (src == nullptr || (needed != 0 && size != needed)) {
+ char ccKey[5];
+ MakeFourCCString(key, ccKey);
+ char ccType[5];
+ MakeFourCCString(type, ccType);
+ if (src == nullptr) {
+ ALOGW("ignoring key '%s' type '%s' missing data (expected %d)",
+ ccKey, ccType, size);
+ } else {
+ ALOGW("ignoring key '%s': type '%s' bytes: expected %d != %d received",
+ ccKey, ccType, needed, size);
+ }
+ } else {
+ setData(key, type, src, size);
+ }
}
}
diff --git a/media/libstagefright/include/media/stagefright/MediaErrors.h b/media/libstagefright/include/media/stagefright/MediaErrors.h
index d1df2ca..b91c850 100644
--- a/media/libstagefright/include/media/stagefright/MediaErrors.h
+++ b/media/libstagefright/include/media/stagefright/MediaErrors.h
@@ -163,11 +163,28 @@
|| (ERROR_DRM_VENDOR_MIN <= err && err <= ERROR_DRM_VENDOR_MAX);
}
-static inline std::string StrCryptoError(status_t err) {
#define STATUS_CASE(STATUS) \
case STATUS: \
return #STATUS
+static inline std::string StrMediaError(status_t err) {
+ switch(err) {
+ STATUS_CASE(ERROR_ALREADY_CONNECTED);
+ STATUS_CASE(ERROR_NOT_CONNECTED);
+ STATUS_CASE(ERROR_UNKNOWN_HOST);
+ STATUS_CASE(ERROR_CANNOT_CONNECT);
+ STATUS_CASE(ERROR_IO);
+ STATUS_CASE(ERROR_CONNECTION_LOST);
+ STATUS_CASE(ERROR_MALFORMED);
+ STATUS_CASE(ERROR_OUT_OF_RANGE);
+ STATUS_CASE(ERROR_BUFFER_TOO_SMALL);
+ STATUS_CASE(ERROR_UNSUPPORTED);
+ STATUS_CASE(ERROR_END_OF_STREAM);
+ }
+ return statusToString(err);
+}
+
+static inline std::string StrCryptoError(status_t err) {
switch (err) {
STATUS_CASE(ERROR_DRM_UNKNOWN);
STATUS_CASE(ERROR_DRM_NO_LICENSE);
@@ -209,10 +226,10 @@
STATUS_CASE(ERROR_DRM_STORAGE_READ);
STATUS_CASE(ERROR_DRM_STORAGE_WRITE);
STATUS_CASE(ERROR_DRM_ZERO_SUBSAMPLES);
-#undef STATUS_CASE
}
return statusToString(err);
}
+#undef STATUS_CASE
} // namespace android
diff --git a/media/libstagefright/omx/OMXStore.cpp b/media/libstagefright/omx/OMXStore.cpp
index e8fee42..7e33f09 100644
--- a/media/libstagefright/omx/OMXStore.cpp
+++ b/media/libstagefright/omx/OMXStore.cpp
@@ -99,6 +99,15 @@
}
}
+static int getFirstApiLevel() {
+ int boardApiLevel = android::base::GetIntProperty("ro.board.first_api_level", 0);
+ if (boardApiLevel != 0) {
+ return boardApiLevel;
+ }
+
+ return android::base::GetIntProperty("ro.product.first_api_level", __ANDROID_API_T__);
+}
+
void OMXStore::addPlugin(OMXPluginBase *plugin) {
Mutex::Autolock autoLock(mLock);
@@ -110,6 +119,29 @@
name, sizeof(name), index++)) == OMX_ErrorNone) {
String8 name8(name);
+ Vector<String8> roles;
+ OMX_ERRORTYPE err = plugin->getRolesOfComponent(name, &roles);
+ if (err == OMX_ErrorNone) {
+ bool skip = false;
+ for (String8 role : roles) {
+ if (role.find("video_decoder") != -1 || role.find("video_encoder") != -1) {
+ if (getFirstApiLevel() >= __ANDROID_API_S__) {
+ skip = true;
+ break;
+ }
+ }
+ if (role.find("audio_decoder") != -1 || role.find("audio_encoder") != -1) {
+ if (getFirstApiLevel() >= __ANDROID_API_T__) {
+ skip = true;
+ break;
+ }
+ }
+ }
+ if (skip) {
+ continue;
+ }
+ }
+
if (mPluginByComponentName.indexOfKey(name8) >= 0) {
ALOGE("A component of name '%s' already exists, ignoring this one.",
name8.string());
diff --git a/media/libstagefright/renderfright/Android.bp b/media/libstagefright/renderfright/Android.bp
index 9a7bad9..3c00a1c 100644
--- a/media/libstagefright/renderfright/Android.bp
+++ b/media/libstagefright/renderfright/Android.bp
@@ -87,7 +87,7 @@
enabled: true,
},
double_loadable: true,
- clang: true,
+
cflags: [
"-fvisibility=hidden",
"-Werror=format",
diff --git a/media/libstagefright/xmlparser/Android.bp b/media/libstagefright/xmlparser/Android.bp
index 055dd80..afc873c 100644
--- a/media/libstagefright/xmlparser/Android.bp
+++ b/media/libstagefright/xmlparser/Android.bp
@@ -41,8 +41,6 @@
"-Wall",
],
- clang: true,
-
sanitize: {
misc_undefined: [
"unsigned-integer-overflow",
diff --git a/media/ndk/NdkImage.cpp b/media/ndk/NdkImage.cpp
index 5fdd45a..12a0d53 100644
--- a/media/ndk/NdkImage.cpp
+++ b/media/ndk/NdkImage.cpp
@@ -25,7 +25,6 @@
#include <android_media_Utils.h>
#include <private/android/AHardwareBufferHelpers.h>
#include <utils/Log.h>
-#include "hardware/camera3.h"
using namespace android;
@@ -375,8 +374,8 @@
uint8_t* jpegBuffer = mLockedBuffer->data;
// First check for JPEG transport header at the end of the buffer
- uint8_t* header = jpegBuffer + (width - sizeof(struct camera3_jpeg_blob));
- struct camera3_jpeg_blob* blob = (struct camera3_jpeg_blob*)(header);
+ uint8_t* header = jpegBuffer + (width - sizeof(struct camera3_jpeg_blob_v2));
+ struct camera3_jpeg_blob_v2* blob = (struct camera3_jpeg_blob_v2*)(header);
if (blob->jpeg_blob_id == CAMERA3_JPEG_BLOB_ID) {
size = blob->jpeg_size;
ALOGV("%s: Jpeg size = %d", __FUNCTION__, size);
diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp
index 6f25cec..38e422d 100644
--- a/media/ndk/NdkMediaCodec.cpp
+++ b/media/ndk/NdkMediaCodec.cpp
@@ -277,8 +277,8 @@
break;
}
msg->findString("detail", &detail);
- ALOGE("Codec reported error(0x%x), actionCode(%d), detail(%s)",
- err, actionCode, detail.c_str());
+ ALOGE("Codec reported error(0x%x/%s), actionCode(%d), detail(%s)",
+ err, StrMediaError(err).c_str(), actionCode, detail.c_str());
Mutex::Autolock _l(mCodec->mAsyncCallbackLock);
if (mCodec->mAsyncCallback.onAsyncError != NULL) {
diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp
index 07fc5de..6d3c348 100644
--- a/media/ndk/NdkMediaExtractor.cpp
+++ b/media/ndk/NdkMediaExtractor.cpp
@@ -388,9 +388,11 @@
mode = CryptoPlugin::kMode_AES_CTR;
}
+ sp<ABuffer> clearbuf;
+ sp<ABuffer> cryptedbuf;
if (sizeof(uint32_t) != sizeof(size_t)) {
- sp<ABuffer> clearbuf = U32ArrayToSizeBuf(numSubSamples, (uint32_t *)cleardata);
- sp<ABuffer> cryptedbuf = U32ArrayToSizeBuf(numSubSamples, (uint32_t *)crypteddata);
+ clearbuf = U32ArrayToSizeBuf(numSubSamples, (uint32_t *)cleardata);
+ cryptedbuf = U32ArrayToSizeBuf(numSubSamples, (uint32_t *)crypteddata);
cleardata = clearbuf == NULL ? NULL : clearbuf->data();
crypteddata = crypteddata == NULL ? NULL : cryptedbuf->data();
if(crypteddata == NULL || cleardata == NULL) {
diff --git a/media/ndk/include/media/NdkMediaCodec.h b/media/ndk/include/media/NdkMediaCodec.h
index 5633374..4938f76 100644
--- a/media/ndk/include/media/NdkMediaCodec.h
+++ b/media/ndk/include/media/NdkMediaCodec.h
@@ -437,18 +437,28 @@
/**
* Set an asynchronous callback for actionable AMediaCodec events.
- * When asynchronous callback is enabled, the client should not call
+ * When asynchronous callback is enabled, it is an error for the client to call
* AMediaCodec_getInputBuffers(), AMediaCodec_getOutputBuffers(),
* AMediaCodec_dequeueInputBuffer() or AMediaCodec_dequeueOutputBuffer().
*
- * Also, AMediaCodec_flush() behaves differently in asynchronous mode.
- * After calling AMediaCodec_flush(), you must call AMediaCodec_start() to
- * "resume" receiving input buffers, even if an input surface was created.
+ * AMediaCodec_flush() behaves differently in asynchronous mode.
+ * After calling AMediaCodec_flush(), the client must call AMediaCodec_start() to
+ * "resume" receiving input buffers. Even if the client does not receive
+ * AMediaCodecOnAsyncInputAvailable callbacks from video encoders configured
+ * with an input surface, the client still needs to call AMediaCodec_start()
+ * to resume the input surface to send buffers to the encoders.
+ *
+ * When called with null callback, this method unregisters any previously set callback.
*
* Refer to the definition of AMediaCodecOnAsyncNotifyCallback on how each
* callback function is called and what are specified.
- * The specified userdata is the pointer used when those callback functions are
- * called.
+ * The specified userdata is opaque data which will be passed along
+ * when the callback functions are called. MediaCodec does not look at or alter the
+ * value of userdata. Often it is a pointer to a client-owned object,
+ * and client manages the lifecycle of the object in that case.
+ *
+ * Once the callback is unregistered or the codec is reset / released, the
+ * previously registered callback will not be called.
*
* All callbacks are fired on one NDK internal thread.
* AMediaCodec_setAsyncNotifyCallback should not be called on the callback thread.
@@ -471,10 +481,17 @@
* render timing samples, and can be significantly delayed and batched. Some frames may have
* been rendered even if there was no callback generated.
*
+ * When called with null callback, this method unregisters any previously set callback.
+ *
* Refer to the definition of AMediaCodecOnFrameRendered on how each
* callback function is called and what are specified.
- * The specified userdata is the pointer used when those callback functions are
- * called.
+ * The specified userdata is opaque data which will be passed along
+ * when the callback functions are called. MediaCodec does not look at or alter the
+ * value of userdata. Often it is a pointer to a client-owned object,
+ * and client manages the lifecycle of the object in that case.
+ *
+ * Once the callback is unregistered or the codec is reset / released, the
+ * previously registered callback will not be called.
*
* All callbacks are fired on one NDK internal thread.
* AMediaCodec_setOnFrameRenderedCallback should not be called on the callback thread.
diff --git a/media/utils/Android.bp b/media/utils/Android.bp
index 3b079c6..a38ef57 100644
--- a/media/utils/Android.bp
+++ b/media/utils/Android.bp
@@ -33,9 +33,11 @@
"MediaUtilsDelayed.cpp",
"MemoryLeakTrackUtil.cpp",
"MethodStatistics.cpp",
+ "Process.cpp",
"ProcessInfo.cpp",
"SchedulingPolicyService.cpp",
"ServiceUtilities.cpp",
+ "ThreadSnapshot.cpp",
"TimeCheck.cpp",
"TimerThread.cpp",
],
diff --git a/media/utils/Process.cpp b/media/utils/Process.cpp
new file mode 100644
index 0000000..8fe8003
--- /dev/null
+++ b/media/utils/Process.cpp
@@ -0,0 +1,69 @@
+/*
+ * 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 "Process"
+#include <utils/Log.h>
+#include <mediautils/Process.h>
+
+#include <android-base/file.h>
+#include <android-base/strings.h>
+#include <cstdlib>
+
+namespace {
+
+void processLine(std::string_view s, std::map<std::string, double>& m) {
+ if (s.empty()) return;
+
+ const size_t colon_pos = s.find(':');
+ if (colon_pos == std::string_view::npos) return;
+
+ const size_t space_pos = s.find(' ');
+ if (space_pos == 0 || space_pos == std::string_view::npos || space_pos > colon_pos) return;
+ std::string key(s.data(), s.data() + space_pos);
+
+ const size_t value_pos = s.find_first_not_of(' ', colon_pos + 1);
+ if (value_pos == std::string_view::npos) return;
+
+ const double value = strtod(s.data() + value_pos, nullptr /* end */);
+ m[std::move(key)] = value;
+}
+
+} // namespace
+
+namespace android::mediautils {
+
+std::string getThreadSchedAsString(pid_t tid) {
+ const pid_t pid = getpid();
+ const std::string path = std::string("/proc/").append(std::to_string(pid))
+ .append("/task/").append(std::to_string(tid)).append("/sched");
+ std::string sched;
+ (void)android::base::ReadFileToString(path.c_str(), &sched);
+ return sched;
+}
+
+std::map<std::string, double> parseThreadSchedString(const std::string& schedString) {
+ std::map<std::string, double> m;
+ if (schedString.empty()) return m;
+ std::vector<std::string> stringlist = android::base::Split(schedString, "\n");
+
+ // OK we use values not strings... m["summary"] = stringlist[0];
+ for (size_t i = 2; i < stringlist.size(); ++i) {
+ processLine(stringlist[i], m);
+ }
+ return m;
+}
+
+} // namespace android::mediautils
diff --git a/media/utils/ThreadSnapshot.cpp b/media/utils/ThreadSnapshot.cpp
new file mode 100644
index 0000000..382738e
--- /dev/null
+++ b/media/utils/ThreadSnapshot.cpp
@@ -0,0 +1,145 @@
+/*
+ * 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 "ThreadSnapshot"
+#include <utils/Log.h>
+#include <utils/Timers.h>
+#include <mediautils/ThreadSnapshot.h>
+
+#include <mediautils/Process.h>
+
+namespace android::mediautils {
+
+pid_t ThreadSnapshot::getTid() const {
+ std::lock_guard lg(mLock);
+ return mState.mTid;
+}
+
+void ThreadSnapshot::setTid(pid_t tid) {
+ std::lock_guard lg(mLock);
+ if (mState.mTid == tid) return;
+ mState.reset(tid);
+}
+
+void ThreadSnapshot::reset() {
+ std::lock_guard lg(mLock);
+ mState.reset(mState.mTid);
+}
+
+void ThreadSnapshot::onBegin() {
+ std::string sched = getThreadSchedAsString(getTid()); // tid could race here,
+ // accept as benign.
+ std::lock_guard lg(mLock);
+ mState.onBegin(std::move(sched));
+}
+
+void ThreadSnapshot::onEnd() {
+ std::lock_guard lg(mLock);
+ mState.onEnd();
+}
+
+std::string ThreadSnapshot::toString() const {
+ // Make a local copy of the stats data under lock.
+ State state;
+ {
+ std::lock_guard lg(mLock);
+ state = mState;
+ }
+ return state.toString();
+}
+
+void ThreadSnapshot::State::reset(pid_t tid) {
+ mTid = tid;
+ mBeginTimeNs = -2;
+ mEndTimeNs = -1;
+ mCumulativeTimeNs = 0;
+ mBeginSched.clear();
+}
+
+void ThreadSnapshot::State::onBegin(std::string sched) {
+ if (mBeginTimeNs < mEndTimeNs) {
+ mBeginTimeNs = systemTime();
+ mBeginSched = std::move(sched);
+ }
+}
+
+void ThreadSnapshot::State::onEnd() {
+ if (mEndTimeNs < mBeginTimeNs) {
+ mEndTimeNs = systemTime();
+ mCumulativeTimeNs += mEndTimeNs - mBeginTimeNs;
+ }
+}
+
+std::string ThreadSnapshot::State::toString() const {
+ if (mBeginTimeNs < 0) return {}; // never begun.
+
+ // compute time intervals.
+ const int64_t nowNs = systemTime();
+ int64_t cumulativeTimeNs = mCumulativeTimeNs;
+ int64_t diffNs = mEndTimeNs - mBeginTimeNs; // if onEnd() isn't matched, diffNs < 0.
+ if (diffNs < 0) {
+ diffNs = nowNs - mBeginTimeNs;
+ cumulativeTimeNs += diffNs;
+ }
+ // normalization for rate variables
+ const double lastRunPerSec = 1e9 / diffNs;
+ const double totalPerSec = 1e9 / cumulativeTimeNs;
+
+ // HANDLE THE SCHEDULER STATISTICS HERE
+ // current and differential statistics for the scheduler.
+ std::string schedNow = getThreadSchedAsString(mTid);
+ const auto schedMapThen = parseThreadSchedString(mBeginSched);
+ const auto schedMapNow = parseThreadSchedString(schedNow);
+ static const char * schedDiffKeyList[] = {
+ "se.sum_exec_runtime",
+ "se.nr_migrations",
+ "se.statistics.wait_sum",
+ "se.statistics.wait_count",
+ "se.statistics.iowait_sum",
+ "se.statistics.iowait_count",
+ "se.statistics.nr_forced_migrations",
+ "nr_involuntary_switches",
+ };
+
+ // compute differential rate statistics.
+ std::string diffString;
+ for (const auto diffKey : schedDiffKeyList) {
+ if (auto itThen = schedMapThen.find(diffKey);
+ itThen != schedMapThen.end()) {
+
+ if (auto itNow = schedMapNow.find(diffKey);
+ itNow != schedMapNow.end()) {
+ auto diff = itNow->second - itThen->second;
+ diff *= lastRunPerSec;
+ auto total = itNow->second * totalPerSec;
+ diffString.append(diffKey).append(" last-run:")
+ .append(std::to_string(diff))
+ .append(" cumulative:")
+ .append(std::to_string(total))
+ .append("\n");
+ }
+ }
+ }
+
+ if (!diffString.empty()) {
+ schedNow.append("*** per second stats ***\n").append(diffString);
+ }
+
+ // Return snapshot string.
+ return schedNow;
+}
+
+} // android::mediautils
diff --git a/media/utils/include/mediautils/Process.h b/media/utils/include/mediautils/Process.h
new file mode 100644
index 0000000..d249c3a
--- /dev/null
+++ b/media/utils/include/mediautils/Process.h
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <map>
+#include <string>
+#include <unistd.h>
+
+/*
+ * This header contains utilities to read the linux system /proc/pid files
+ *
+ * The format of this is not guaranteed to be stable, so use for diagnostic purposes only.
+ *
+ * The linux "proc" directory documentation:
+ * https://kernel.org/doc/Documentation/filesystems/proc.txt
+ * https://www.kernel.org/doc/html/latest/filesystems/proc.html?highlight=proc%20pid#chapter-3-per-process-parameters
+ */
+
+namespace android::mediautils {
+
+/**
+ * Return the thread schedule information for tid.
+ *
+ * String will be empty if the process does not have permission to
+ * access the /proc/pid tables, or if not on a Linux device.
+ *
+ * Linux scheduler documentation:
+ * https://www.kernel.org/doc/html/latest/scheduler/index.html
+ * https://man7.org/linux/man-pages/man7/sched.7.html
+ *
+ * Sample as follows:
+
+AudioOut_8D (10800, #threads: 36)
+-------------------------------------------------------------------
+se.exec_start : 8132077.598026
+se.vruntime : 798689.872087
+se.sum_exec_runtime : 136466.957838
+se.nr_migrations : 132487
+se.statistics.sum_sleep_runtime : 5629794.565945
+se.statistics.wait_start : 0.000000
+se.statistics.sleep_start : 8195727.586392
+se.statistics.block_start : 0.000000
+se.statistics.sleep_max : 1995665.869808
+se.statistics.block_max : 0.591675
+se.statistics.exec_max : 2.477580
+se.statistics.slice_max : 0.000000
+se.statistics.wait_max : 8.608642
+se.statistics.wait_sum : 4683.266835
+se.statistics.wait_count : 300964
+se.statistics.iowait_sum : 0.000000
+se.statistics.iowait_count : 0
+se.statistics.nr_migrations_cold : 0
+se.statistics.nr_failed_migrations_affine : 297
+se.statistics.nr_failed_migrations_running : 1412
+se.statistics.nr_failed_migrations_hot : 96
+se.statistics.nr_forced_migrations : 26
+se.statistics.nr_wakeups : 281263
+se.statistics.nr_wakeups_sync : 84
+se.statistics.nr_wakeups_migrate : 132322
+se.statistics.nr_wakeups_local : 2165
+se.statistics.nr_wakeups_remote : 279098
+se.statistics.nr_wakeups_affine : 0
+se.statistics.nr_wakeups_affine_attempts : 0
+se.statistics.nr_wakeups_passive : 0
+se.statistics.nr_wakeups_idle : 0
+avg_atom : 0.453434
+avg_per_cpu : 1.030040
+nr_switches : 300963
+nr_voluntary_switches : 281252
+nr_involuntary_switches : 19711
+se.load.weight : 73477120
+se.avg.load_sum : 58
+se.avg.runnable_sum : 27648
+se.avg.util_sum : 21504
+se.avg.load_avg : 48
+se.avg.runnable_avg : 0
+se.avg.util_avg : 0
+se.avg.last_update_time : 8132075824128
+se.avg.util_est.ewma : 8
+se.avg.util_est.enqueued : 1
+uclamp.min : 0
+uclamp.max : 1024
+effective uclamp.min : 0
+effective uclamp.max : 1024
+policy : 0
+prio : 101
+clock-delta : 163
+*/
+std::string getThreadSchedAsString(pid_t tid);
+
+/**
+ * Returns map for the raw thread schedule string.
+ */
+std::map<std::string, double> parseThreadSchedString(const std::string& schedString);
+
+/**
+ * Returns map for /proc/pid/task/tid/sched
+ */
+inline std::map<std::string, double> getThreadSchedAsMap(pid_t tid) {
+ return parseThreadSchedString(getThreadSchedAsString(tid));
+}
+
+// TODO: Extend to other /proc/pid file information.
+//
+// See "ps" command get_ps().
+// https://cs.android.com/android/platform/superproject/+/master:external/toybox/toys/posix/ps.c;l=707
+
+} // android::mediautils
diff --git a/media/utils/include/mediautils/ScopedStatistics.h b/media/utils/include/mediautils/ScopedStatistics.h
new file mode 100644
index 0000000..c5fc1e9
--- /dev/null
+++ b/media/utils/include/mediautils/ScopedStatistics.h
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "MethodStatistics.h"
+#include <chrono>
+#include <memory>
+#include <string>
+#include <utility>
+
+namespace android::mediautils {
+
+class ScopedStatistics {
+ public:
+ /**
+ * ScopedStatistics is a RAII way of obtaining
+ * execution time statistics for a scoped C++ block.
+ *
+ * It updates the MethodStatistics shared pointer parameter
+ * with the methodName parameter and the duration/lifetime of the
+ * ScopedStatistics object.
+ *
+ * Not thread-safe, but expected to run in a single execution
+ * thread, and there are no user serviceable parts exposed.
+ *
+ * Example:
+ *
+ * std::shared_ptr<mediautils::MethodStatistics<std::string>> stats =
+ * std::make_shared<mediautils::MethodStatistics<std::string>>();
+ *
+ * // ...
+ * {
+ * mediautils::ScopedStatistics scopedStatistics("MyClass:myMethod", stats);
+ *
+ * // some work to be timed here - up to the end of the block.
+ * }
+ *
+ * \param methodName the methodname to use "ClassName::methodName"
+ * \param statistics a shared ptr to the MethodStatistics object to use.
+ */
+ ScopedStatistics(std::string methodName,
+ std::shared_ptr<mediautils::MethodStatistics<std::string>> statistics)
+ : mMethodName{std::move(methodName)}
+ , mStatistics{std::move(statistics)}
+ , mBegin{std::chrono::steady_clock::now()} {}
+
+ // No copy constructor.
+ ScopedStatistics(const ScopedStatistics& scopedStatistics) = delete;
+ ScopedStatistics& operator=(const ScopedStatistics& scopedStatistics) = delete;
+
+ ~ScopedStatistics() {
+ if (mStatistics) {
+ const float elapsedMs = std::chrono::duration_cast<std::chrono::nanoseconds>(
+ std::chrono::steady_clock::now() - mBegin)
+ .count() *
+ 1e-6; // ns to ms.
+ mStatistics->event(mMethodName, elapsedMs);
+ }
+ }
+
+ private:
+ const std::string mMethodName;
+ const std::shared_ptr<mediautils::MethodStatistics<std::string>> mStatistics;
+ const std::chrono::steady_clock::time_point mBegin;
+};
+
+} // namespace android::mediautils
diff --git a/media/utils/include/mediautils/ThreadSnapshot.h b/media/utils/include/mediautils/ThreadSnapshot.h
new file mode 100644
index 0000000..c470822
--- /dev/null
+++ b/media/utils/include/mediautils/ThreadSnapshot.h
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <mutex>
+#include <string>
+
+#include <android-base/thread_annotations.h>
+
+namespace android::mediautils {
+
+/**
+ * Collect Thread performance statistics.
+ *
+ * An onBegin() and onEnd() signal a continuous "run".
+ * Statistics are returned by toString().
+ */
+class ThreadSnapshot {
+public:
+ explicit ThreadSnapshot(pid_t tid = -1) { mState.reset(tid); };
+
+ // Returns current tid
+ pid_t getTid() const;
+
+ // Sets the tid
+ void setTid(pid_t tid);
+
+ // Reset statistics, keep same tid.
+ void reset();
+
+ // Signal a timing run is beginning
+ void onBegin();
+
+ // Signal a timing run is ending
+ void onEnd();
+
+ // Return the thread snapshot statistics in a string
+ std::string toString() const;
+
+private:
+ mutable std::mutex mLock;
+
+ // State represents our statistics at a given point in time.
+ // It is not thread-safe, so any locking must occur at the caller.
+ struct State {
+ pid_t mTid;
+ int64_t mBeginTimeNs; // when last run began
+ int64_t mEndTimeNs; // when last run ends (if less than begin time, not started)
+ int64_t mCumulativeTimeNs;
+
+ // Sched is the scheduler statistics obtained as a string.
+ // This is parsed only when toString() is called.
+ std::string mBeginSched;
+
+ // Clears existing state.
+ void reset(pid_t tid);
+
+ // onBegin() takes a std::string sched should can be captured outside
+ // of locking.
+ void onBegin(std::string sched);
+ void onEnd();
+ std::string toString() const;
+ };
+
+ // Our current state. We only keep the current running state.
+ State mState GUARDED_BY(mLock);
+};
+
+} // android::mediautils
diff --git a/media/utils/tests/Android.bp b/media/utils/tests/Android.bp
index 30c10b7..1024018 100644
--- a/media/utils/tests/Android.bp
+++ b/media/utils/tests/Android.bp
@@ -64,6 +64,26 @@
}
cc_test {
+ name: "media_process_tests",
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+
+ shared_libs: [
+ "liblog",
+ "libmediautils",
+ "libutils",
+ ],
+
+ srcs: [
+ "media_process_tests.cpp",
+ ],
+}
+
+cc_test {
name: "media_synchronization_tests",
cflags: [
@@ -84,6 +104,47 @@
}
cc_test {
+ name: "media_threadsnapshot_tests",
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+
+ shared_libs: [
+ "liblog",
+ "libmediautils",
+ "libutils",
+ ],
+
+ srcs: [
+ "media_threadsnapshot_tests.cpp",
+ ],
+}
+
+cc_test {
+ name: "mediautils_scopedstatistics_tests",
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+
+ shared_libs: [
+ "libaudioutils",
+ "liblog",
+ "libmediautils",
+ "libutils",
+ ],
+
+ srcs: [
+ "mediautils_scopedstatistics_tests.cpp",
+ ],
+}
+
+cc_test {
name: "methodstatistics_tests",
cflags: [
diff --git a/media/utils/tests/media_process_tests.cpp b/media/utils/tests/media_process_tests.cpp
new file mode 100644
index 0000000..2ae3f70
--- /dev/null
+++ b/media/utils/tests/media_process_tests.cpp
@@ -0,0 +1,101 @@
+/*
+ * 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 <mediautils/Process.h>
+
+#define LOG_TAG "media_process_tests"
+
+#include <gtest/gtest.h>
+#include <utils/Log.h>
+
+using namespace android;
+using namespace android::mediautils;
+
+TEST(media_process_tests, basic) {
+ const std::string schedString = getThreadSchedAsString(gettid());
+
+ (void)schedString;
+ // We don't test schedString, only that we haven't crashed.
+ // ASSERT_FALSE(schedString.empty());
+
+ // schedString is not normative. So we conjure up our own string
+ const std::string fakeString = "\
+AudioOut_8D (10800, #threads: 36)\n\
+-------------------------------------------------------------------\n\
+se.exec_start : 8132077.598026\n\
+se.vruntime : 798689.872087\n\
+se.sum_exec_runtime : 136466.957838\n\
+se.nr_migrations : 132487\n\
+se.statistics.sum_sleep_runtime : 5629794.565945\n\
+se.statistics.wait_start : 0.000000\n\
+se.statistics.sleep_start : 8195727.586392\n\
+se.statistics.block_start : 0.000000\n\
+se.statistics.sleep_max : 1995665.869808\n\
+se.statistics.block_max : 0.591675\n\
+se.statistics.exec_max : 2.477580\n\
+se.statistics.slice_max : 0.000000\n\
+se.statistics.wait_max : 8.608642\n\
+se.statistics.wait_sum : 4683.266835\n\
+se.statistics.wait_count : 300964\n\
+se.statistics.iowait_sum : 0.000000\n\
+se.statistics.iowait_count : 0\n\
+se.statistics.nr_migrations_cold : 0\n\
+se.statistics.nr_failed_migrations_affine : 297\n\
+se.statistics.nr_failed_migrations_running : 1412\n\
+se.statistics.nr_failed_migrations_hot : 96\n\
+se.statistics.nr_forced_migrations : 26\n\
+se.statistics.nr_wakeups : 281263\n\
+se.statistics.nr_wakeups_sync : 84\n\
+se.statistics.nr_wakeups_migrate : 132322\n\
+se.statistics.nr_wakeups_local : 2165\n\
+se.statistics.nr_wakeups_remote : 279098\n\
+se.statistics.nr_wakeups_affine : 0\n\
+se.statistics.nr_wakeups_affine_attempts : 0\n\
+se.statistics.nr_wakeups_passive : 0\n\
+se.statistics.nr_wakeups_idle : 0\n\
+avg_atom : 0.453434\n\
+avg_per_cpu : 1.030040\n\
+nr_switches : 300963\n\
+nr_voluntary_switches : 281252\n\
+nr_involuntary_switches : 19711\n\
+se.load.weight : 73477120\n\
+se.avg.load_sum : 58\n\
+se.avg.runnable_sum : 27648\n\
+se.avg.util_sum : 21504\n\
+se.avg.load_avg : 48\n\
+se.avg.runnable_avg : 0\n\
+se.avg.util_avg : 0\n\
+se.avg.last_update_time : 8132075824128\n\
+se.avg.util_est.ewma : 8\n\
+se.avg.util_est.enqueued : 1\n\
+uclamp.min : 0\n\
+uclamp.max : 1024\n\
+effective uclamp.min : 0\n\
+effective uclamp.max : 1024\n\
+policy : 0\n\
+prio : 101\n\
+clock-delta : 163";
+
+ std::map<std::string, double> m = parseThreadSchedString(fakeString);
+
+ auto it = m.find("clock-delta");
+ ASSERT_NE(it, m.end());
+ ASSERT_EQ(it->second, 163);
+
+ it = m.find("se.avg.load_avg");
+ ASSERT_NE(it, m.end());
+ ASSERT_EQ(it->second, 48);
+}
diff --git a/media/utils/tests/media_threadsnapshot_tests.cpp b/media/utils/tests/media_threadsnapshot_tests.cpp
new file mode 100644
index 0000000..c7a45e2
--- /dev/null
+++ b/media/utils/tests/media_threadsnapshot_tests.cpp
@@ -0,0 +1,52 @@
+/*
+ * 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 <mediautils/ThreadSnapshot.h>
+
+#define LOG_TAG "media_threadsnapshot_tests"
+
+#include <gtest/gtest.h>
+#include <utils/Log.h>
+
+#include <chrono>
+#include <thread>
+
+using namespace android;
+using namespace android::mediautils;
+
+TEST(media_threadsnapshot_tests, basic) {
+ using namespace std::chrono_literals;
+
+ ThreadSnapshot threadSnapshot(gettid());
+
+ threadSnapshot.onBegin();
+
+ std::string snapshot1 = threadSnapshot.toString();
+
+ std::this_thread::sleep_for(100ms);
+
+ threadSnapshot.onEnd();
+
+ std::string snapshot2 = threadSnapshot.toString();
+
+ // Either we can't get a snapshot, or they must be different when taken when thread is running.
+ if (snapshot1.empty()) {
+ ASSERT_TRUE(snapshot2.empty());
+ } else {
+ ASSERT_FALSE(snapshot2.empty());
+ ASSERT_NE(snapshot1, snapshot2);
+ }
+}
diff --git a/media/utils/tests/mediautils_scopedstatistics_tests.cpp b/media/utils/tests/mediautils_scopedstatistics_tests.cpp
new file mode 100644
index 0000000..807ce63
--- /dev/null
+++ b/media/utils/tests/mediautils_scopedstatistics_tests.cpp
@@ -0,0 +1,54 @@
+/*
+ * 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 "mediautils_scopedstatistics_tests"
+
+#include <mediautils/ScopedStatistics.h>
+
+#include <atomic>
+#include <chrono>
+#include <gtest/gtest.h>
+#include <thread>
+#include <utils/Log.h>
+
+using namespace android::mediautils;
+using namespace std::chrono_literals;
+
+TEST(mediautils_scopedstatistics_tests, basic) {
+ auto methodStatistics = std::make_shared<MethodStatistics<std::string>>();
+ std::string METHOD_NAME{"MyMethod"};
+
+ // no stats before
+ auto empty = methodStatistics->getStatistics(METHOD_NAME);
+ ASSERT_EQ(0, empty.getN());
+
+ // create a scoped statistics object.
+ {
+ ScopedStatistics scopedStatistics(METHOD_NAME, methodStatistics);
+
+ std::this_thread::sleep_for(100ms);
+ }
+
+ // check that some stats were logged.
+ auto stats = methodStatistics->getStatistics(METHOD_NAME);
+ ASSERT_EQ(1, stats.getN());
+ auto mean = stats.getMean();
+
+ // mean should be about 100ms, but to avoid false failures,
+ // we check 50ms < mean < 300ms.
+ ASSERT_GT(mean, 50.); // took more than 50ms.
+ ASSERT_LT(mean, 300.); // took less than 300ms.
+}
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 59f22eb..8e4383c 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -76,6 +76,7 @@
#include <media/VolumeShaper.h>
#include <mediautils/ServiceUtilities.h>
#include <mediautils/Synchronization.h>
+#include <mediautils/ThreadSnapshot.h>
#include <audio_utils/clock.h>
#include <audio_utils/FdToString.h>
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 0f27f90..49f6bfc 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -65,6 +65,7 @@
#include <media/nbaio/PipeReader.h>
#include <media/nbaio/SourceAudioBufferProvider.h>
#include <mediautils/BatteryNotifier.h>
+#include <mediautils/Process.h>
#include <audiomanager/AudioManager.h>
#include <powermanager/PowerManager.h>
@@ -923,6 +924,20 @@
dprintf(fd, " Local log:\n");
mLocalLog.dump(fd, " " /* prefix */, 40 /* lines */);
+
+ // --all does the statistics
+ bool dumpAll = false;
+ for (const auto &arg : args) {
+ if (arg == String16("--all")) {
+ dumpAll = true;
+ }
+ }
+ if (dumpAll || type() == SPATIALIZER) {
+ const std::string sched = mThreadSnapshot.toString();
+ if (!sched.empty()) {
+ (void)write(fd, sched.c_str(), sched.size());
+ }
+ }
}
void AudioFlinger::ThreadBase::dumpBase_l(int fd, const Vector<String16>& args __unused)
@@ -963,7 +978,8 @@
|| mType == MIXER
|| mType == DUPLICATING
|| mType == DIRECT
- || mType == OFFLOAD) {
+ || mType == OFFLOAD
+ || mType == SPATIALIZER) {
dprintf(fd, " Timestamp stats: %s\n", mTimestampVerifier.toString().c_str());
dprintf(fd, " Timestamp corrected: %s\n", isTimestampCorrectionEnabled() ? "yes" : "no");
}
@@ -2098,6 +2114,7 @@
}
}
run(mThreadName, ANDROID_PRIORITY_URGENT_AUDIO);
+ mThreadSnapshot.setTid(getTid());
}
// ThreadBase virtuals
@@ -2991,6 +3008,7 @@
// Calculate size of normal sink buffer relative to the HAL output buffer size
double multiplier = 1.0;
+ // Note: mType == SPATIALIZER does not support FastMixer.
if (mType == MIXER && (kUseFastMixer == FastMixer_Static ||
kUseFastMixer == FastMixer_Dynamic)) {
size_t minNormalFrameCount = (kMinNormalSinkBufferSizeMs * mSampleRate) / 1000;
@@ -3339,6 +3357,7 @@
mInWrite = false;
if (mStandby) {
mThreadMetrics.logBeginInterval();
+ mThreadSnapshot.onBegin();
mStandby = false;
}
return bytesWritten;
@@ -3451,7 +3470,7 @@
sp<EffectBufferHalInterface> halInBuffer, halOutBuffer;
effect_buffer_t *buffer = nullptr; // only used for non global sessions
- if (mType == SPATIALIZER ) {
+ if (mType == SPATIALIZER) {
if (!audio_is_global_session(session)) {
// player sessions on a spatializer output will use a dedicated input buffer and
// will either output multi channel to mEffectBuffer if the track is spatilaized
@@ -3677,7 +3696,7 @@
cacheParameters_l();
mSleepTimeUs = mIdleSleepTimeUs;
- if (mType == MIXER) {
+ if (mType == MIXER || mType == SPATIALIZER) {
sleepTimeShift = 0;
}
@@ -3824,6 +3843,7 @@
if (!mStandby) {
LOG_AUDIO_STATE();
mThreadMetrics.logEndInterval();
+ mThreadSnapshot.onEnd();
mStandby = true;
}
sendStatistics(false /* force */);
@@ -3854,7 +3874,7 @@
mStandbyTimeNs = systemTime() + mStandbyDelayNs;
mSleepTimeUs = mIdleSleepTimeUs;
- if (mType == MIXER) {
+ if (mType == MIXER || mType == SPATIALIZER) {
sleepTimeShift = 0;
}
@@ -4131,7 +4151,8 @@
// write blocked detection
const int64_t deltaWriteNs = lastIoEndNs - lastIoBeginNs;
- if (mType == MIXER && deltaWriteNs > maxPeriod) {
+ if ((mType == MIXER || mType == SPATIALIZER)
+ && deltaWriteNs > maxPeriod) {
mNumDelayedWrites++;
if ((lastIoEndNs - lastWarning) > kWarningThrottleNs) {
ATRACE_NAME("underrun");
@@ -4152,7 +4173,7 @@
(mMixerStatus == MIXER_DRAIN_ALL)) {
threadLoop_drain();
}
- if (mType == MIXER && !mStandby) {
+ if ((mType == MIXER || mType == SPATIALIZER) && !mStandby) {
if (mThreadThrottle
&& mMixerStatus == MIXER_TRACKS_READY // we are mixing (active tracks)
@@ -4277,13 +4298,6 @@
void AudioFlinger::PlaybackThread::collectTimestamps_l()
{
- // Collect timestamp statistics for the Playback Thread types that support it.
- if (mType != MIXER
- && mType != DUPLICATING
- && mType != DIRECT
- && mType != OFFLOAD) {
- return;
- }
if (mStandby) {
mTimestampVerifier.discontinuity(discontinuityForStandbyOrFlush());
return;
@@ -5959,6 +5973,7 @@
mOutput->standby();
if (!mStandby) {
mThreadMetrics.logEndInterval();
+ mThreadSnapshot.onEnd();
mStandby = true;
}
mBytesWritten = 0;
@@ -6480,6 +6495,7 @@
mOutput->standby();
if (!mStandby) {
mThreadMetrics.logEndInterval();
+ mThreadSnapshot.onEnd();
mStandby = true;
}
mBytesWritten = 0;
@@ -7066,6 +7082,7 @@
}
if (mStandby) {
mThreadMetrics.logBeginInterval();
+ mThreadSnapshot.onBegin();
mStandby = false;
}
return (ssize_t)mSinkBufferSize;
@@ -7591,6 +7608,7 @@
doBroadcast = true;
if (mStandby) {
mThreadMetrics.logBeginInterval();
+ mThreadSnapshot.onBegin();
mStandby = false;
}
activeTrack->mState = TrackBase::ACTIVE;
@@ -8072,6 +8090,7 @@
if (!mStandby) {
inputStandBy();
mThreadMetrics.logEndInterval();
+ mThreadSnapshot.onEnd();
mStandby = true;
}
}
@@ -9457,6 +9476,7 @@
}
if (mStandby) {
mThreadMetrics.logBeginInterval();
+ mThreadSnapshot.onBegin();
mStandby = false;
}
return NO_ERROR;
@@ -9653,6 +9673,7 @@
mHalStream->standby();
if (!mStandby) {
mThreadMetrics.logEndInterval();
+ mThreadSnapshot.onEnd();
mStandby = true;
}
releaseWakeLock();
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 1fccdc5..b2962ed8 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -687,6 +687,9 @@
int64_t mLastIoBeginNs = -1;
int64_t mLastIoEndNs = -1;
+ // ThreadSnapshot is thread-safe (internally locked)
+ mediautils::ThreadSnapshot mThreadSnapshot;
+
// This should be read under ThreadBase lock (if not on the threadLoop thread).
audio_utils::Statistics<double> mIoJitterMs{0.995 /* alpha */};
audio_utils::Statistics<double> mProcessTimeMs{0.995 /* alpha */};
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 20d0523..496591a 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -533,6 +533,10 @@
virtual void onRoutingUpdated() = 0;
+ // Used to notify AudioService that an error was encountering when reading
+ // the volume ranges, and that they should be re-initialized
+ virtual void onVolumeRangeInitRequest() = 0;
+
// Used to notify the sound trigger module that an audio capture is about to
// take place. This should typically result in any active recognition
// sessions to be preempted on modules that do not support sound trigger
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index 64c7923..75fa595 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -518,6 +518,14 @@
uint32_t inPastMs = 0, nsecs_t sysTime = 0) const;
/**
+ * @brief isStrategyActive checks if the given strategy is active
+ * on the given output
+ * @param ps product strategy to be checked upon activity status
+ * @return true if an output following the strategy is active, false otherwise
+ */
+ bool isStrategyActive(product_strategy_t ps) const;
+
+ /**
* @brief clearSessionRoutesForDevice: when a device is disconnected, and if this device has
* been chosen as the preferred device by any client, the policy manager shall
* prevent from using this device any more by clearing all the session routes involving this
@@ -562,6 +570,11 @@
sp<SwAudioOutputDescriptor> getOutputForClient(audio_port_handle_t portId);
+ /**
+ * return whether any output is active and routed to any of the specified devices
+ */
+ bool isAnyDeviceTypeActive(const DeviceTypeSet& deviceTypes) const;
+
void dump(String8 *dst) const;
};
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 009fa82..40a1eaa 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -841,6 +841,16 @@
return false;
}
+bool SwAudioOutputCollection::isStrategyActive(product_strategy_t ps) const
+{
+ for (size_t i = 0; i < size(); i++) {
+ if (valueAt(i)->isStrategyActive(ps)) {
+ return true;
+ }
+ }
+ return false;
+}
+
audio_io_handle_t SwAudioOutputCollection::getA2dpOutput() const
{
for (size_t i = 0; i < size(); i++) {
@@ -916,6 +926,16 @@
}
}
}
+bool SwAudioOutputCollection::isAnyDeviceTypeActive(const DeviceTypeSet& deviceTypes) const {
+ for (size_t i = 0; i < size(); i++) {
+ const sp<SwAudioOutputDescriptor> outputDesc = valueAt(i);
+ if (outputDesc->isActive()
+ && outputDesc->devices().containsDeviceAmongTypes(deviceTypes)) {
+ return true;
+ }
+ }
+ return false;
+}
void SwAudioOutputCollection::dump(String8 *dst) const
{
diff --git a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
index d1655ef..713b0ac 100644
--- a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
@@ -125,7 +125,7 @@
void SourceClientCollection::dump(String8 *dst) const
{
- dst->append("\n Audio sources (%zu):\n", size());
+ dst->appendFormat("\n Audio sources (%zu):\n", size());
for (size_t i = 0; i < size(); i++) {
const std::string prefix = base::StringPrintf(" %zu. ", i + 1);
dst->appendFormat("%s", prefix.c_str());
diff --git a/services/audiopolicy/config/bluetooth_with_le_audio_policy_configuration.xml b/services/audiopolicy/config/bluetooth_with_le_audio_policy_configuration.xml
index 22ff954..d34cca0 100644
--- a/services/audiopolicy/config/bluetooth_with_le_audio_policy_configuration.xml
+++ b/services/audiopolicy/config/bluetooth_with_le_audio_policy_configuration.xml
@@ -11,17 +11,7 @@
channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
</mixPort>
<!-- Le Audio Audio Ports -->
- <mixPort name="le audio output" role="source">
- <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
- samplingRates="8000,16000,24000,32000,44100,48000"
- channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO"/>
- <profile name="" format="AUDIO_FORMAT_PCM_24_BIT_PACKED"
- samplingRates="8000,16000,24000,32000,44100,48000"
- channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO"/>
- <profile name="" format="AUDIO_FORMAT_PCM_32_BIT"
- samplingRates="8000,16000,24000,32000,44100,48000"
- channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO"/>
- </mixPort>
+ <mixPort name="le audio output" role="source"/>
<mixPort name="le audio input" role="sink">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="8000,16000,24000,32000,44100,48000"
diff --git a/services/audiopolicy/config/bluetooth_with_le_audio_policy_configuration_7_0.xml b/services/audiopolicy/config/bluetooth_with_le_audio_policy_configuration_7_0.xml
index aad00d6..e7908eb 100644
--- a/services/audiopolicy/config/bluetooth_with_le_audio_policy_configuration_7_0.xml
+++ b/services/audiopolicy/config/bluetooth_with_le_audio_policy_configuration_7_0.xml
@@ -11,17 +11,7 @@
channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
</mixPort>
<!-- Le Audio Audio Ports -->
- <mixPort name="le audio output" role="source">
- <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
- samplingRates="8000 16000 24000 32000 44100 48000"
- channelMasks="AUDIO_CHANNEL_OUT_MONO AUDIO_CHANNEL_OUT_STEREO"/>
- <profile name="" format="AUDIO_FORMAT_PCM_24_BIT_PACKED"
- samplingRates="8000 16000 24000 32000 44100 48000"
- channelMasks="AUDIO_CHANNEL_OUT_MONO AUDIO_CHANNEL_OUT_STEREO"/>
- <profile name="" format="AUDIO_FORMAT_PCM_32_BIT"
- samplingRates="8000 16000 24000 32000 44100 48000"
- channelMasks="AUDIO_CHANNEL_OUT_MONO AUDIO_CHANNEL_OUT_STEREO"/>
- </mixPort>
+ <mixPort name="le audio output" role="source" />
<mixPort name="le audio input" role="sink">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="8000 16000 24000 32000 44100 48000"
diff --git a/services/audiopolicy/engine/common/include/EngineBase.h b/services/audiopolicy/engine/common/include/EngineBase.h
index 0f8b0a5..7d21ae0 100644
--- a/services/audiopolicy/engine/common/include/EngineBase.h
+++ b/services/audiopolicy/engine/common/include/EngineBase.h
@@ -87,10 +87,17 @@
status_t listAudioVolumeGroups(AudioVolumeGroupVector &groups) const override;
+ /**
+ * Get the list of currently connected removable device types ordered from most recently
+ * connected to least recently connected.
+ * @param group the device group to consider: wired, a2dp... If none, consider all groups.
+ * @param excludedDevices list of device types to ignore
+ * @return a potentially empty ordered list of connected removable devices.
+ */
std::vector<audio_devices_t> getLastRemovableMediaDevices(
- device_out_group_t group = GROUP_NONE) const
- {
- return mLastRemovableMediaDevices.getLastRemovableMediaDevices(group);
+ device_out_group_t group = GROUP_NONE,
+ std::vector<audio_devices_t> excludedDevices = {}) const {
+ return mLastRemovableMediaDevices.getLastRemovableMediaDevices(group, excludedDevices);
}
void dump(String8 *dst) const override;
diff --git a/services/audiopolicy/engine/common/include/LastRemovableMediaDevices.h b/services/audiopolicy/engine/common/include/LastRemovableMediaDevices.h
index d7f8b1e..2662cd3 100644
--- a/services/audiopolicy/engine/common/include/LastRemovableMediaDevices.h
+++ b/services/audiopolicy/engine/common/include/LastRemovableMediaDevices.h
@@ -35,7 +35,8 @@
public:
void setRemovableMediaDevices(sp<DeviceDescriptor> desc, audio_policy_dev_state_t state);
std::vector<audio_devices_t> getLastRemovableMediaDevices(
- device_out_group_t group = GROUP_NONE) const;
+ device_out_group_t group = GROUP_NONE,
+ std::vector<audio_devices_t> excludedDevices = {}) const;
sp<DeviceDescriptor> getLastRemovableMediaDevice(
const DeviceVector& excludedDevices, device_out_group_t group = GROUP_NONE) const;
diff --git a/services/audiopolicy/engine/common/src/EngineBase.cpp b/services/audiopolicy/engine/common/src/EngineBase.cpp
index 7a06206..99507ee 100644
--- a/services/audiopolicy/engine/common/src/EngineBase.cpp
+++ b/services/audiopolicy/engine/common/src/EngineBase.cpp
@@ -72,9 +72,12 @@
{
audio_devices_t deviceType = devDesc->type();
if ((deviceType != AUDIO_DEVICE_NONE) && audio_is_output_device(deviceType)
- && deviceType != AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) {
+ && deviceType != AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET
+ && deviceType != AUDIO_DEVICE_OUT_BLE_BROADCAST) {
// USB dock does not follow the rule of last removable device connected wins.
// It is only used if no removable device is connected or if set as preferred device
+ // LE audio broadcast device has a specific policy depending on active strategies and
+ // devices and does not follow the rule of last connected removable device.
mLastRemovableMediaDevices.setRemovableMediaDevices(devDesc, state);
}
diff --git a/services/audiopolicy/engine/common/src/LastRemovableMediaDevices.cpp b/services/audiopolicy/engine/common/src/LastRemovableMediaDevices.cpp
index 06cc799..93122e0 100644
--- a/services/audiopolicy/engine/common/src/LastRemovableMediaDevices.cpp
+++ b/services/audiopolicy/engine/common/src/LastRemovableMediaDevices.cpp
@@ -44,12 +44,15 @@
}
std::vector<audio_devices_t> LastRemovableMediaDevices::getLastRemovableMediaDevices(
- device_out_group_t group) const
+ device_out_group_t group, std::vector<audio_devices_t> excludedDevices) const
{
std::vector<audio_devices_t> ret;
for (auto iter = mMediaDevices.begin(); iter != mMediaDevices.end(); ++iter) {
- if ((group == GROUP_NONE) || (group == getDeviceOutGroup((iter->desc)->type()))) {
- ret.push_back((iter->desc)->type());
+ audio_devices_t type = (iter->desc)->type();
+ if ((group == GROUP_NONE || group == getDeviceOutGroup(type))
+ && std::find(excludedDevices.begin(), excludedDevices.end(), type) ==
+ excludedDevices.end()) {
+ ret.push_back(type);
}
}
return ret;
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index dc34a38..95aacb2 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -270,7 +270,7 @@
devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_HEARING_AID);
if (!devices.isEmpty()) break;
devices = availableOutputDevices.getFirstDevicesFromTypes(
- getLastRemovableMediaDevices());
+ getLastRemovableMediaDevices(GROUP_NONE, {AUDIO_DEVICE_OUT_BLE_HEADSET}));
if (!devices.isEmpty()) break;
devices = availableOutputDevices.getFirstDevicesFromTypes({
AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET, AUDIO_DEVICE_OUT_EARPIECE});
@@ -344,6 +344,30 @@
(getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) == AUDIO_POLICY_FORCE_SPEAKER)) {
devices2 = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER);
}
+
+ // LE audio broadcast device is only used if:
+ // - No call is active
+ // - either MEDIA or SONIFICATION_RESPECTFUL is the highest priority active strategy
+ // OR the LE audio unicast device is not active
+ if (devices2.isEmpty() && !isInCall()
+ && (strategy == STRATEGY_MEDIA || strategy == STRATEGY_SONIFICATION_RESPECTFUL)) {
+ legacy_strategy topActiveStrategy = STRATEGY_NONE;
+ for (const auto &ps : getOrderedProductStrategies()) {
+ if (outputs.isStrategyActive(ps)) {
+ topActiveStrategy = mLegacyStrategyMap.find(ps) != end(mLegacyStrategyMap) ?
+ mLegacyStrategyMap.at(ps) : STRATEGY_NONE;
+ break;
+ }
+ }
+
+ if (topActiveStrategy == STRATEGY_NONE || topActiveStrategy == STRATEGY_MEDIA
+ || topActiveStrategy == STRATEGY_SONIFICATION_RESPECTFUL
+ || !outputs.isAnyDeviceTypeActive(getAudioDeviceOutLeAudioUnicastSet())) {
+ devices2 =
+ availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_BLE_BROADCAST);
+ }
+ }
+
if (devices2.isEmpty() && (getLastRemovableMediaDevices().size() > 0)) {
if ((getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP)) {
// Get the last connected device of wired and bluetooth a2dp
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index f08d4ad..744609f 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -190,6 +190,9 @@
// save a copy of the opened output descriptors before any output is opened or closed
// by checkOutputsForDevice(). This will be needed by checkOutputForAllStrategies()
mPreviousOutputs = mOutputs;
+
+ bool wasLeUnicastActive = isLeUnicastActive();
+
switch (state)
{
// handle output device connection
@@ -287,9 +290,12 @@
sp<SwAudioOutputDescriptor> desc = mOutputs.valueFor(output);
// close unused outputs after device disconnection or direct outputs that have
// been opened by checkOutputsForDevice() to query dynamic parameters
+ // "outputs" vector never contains duplicated outputs
if ((state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE)
|| (((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) &&
- (desc->mDirectOpenCount == 0))) {
+ (desc->mDirectOpenCount == 0))
+ || (((desc->mFlags & AUDIO_OUTPUT_FLAG_SPATIALIZER) != 0) &&
+ !isOutputOnlyAvailableRouteToSomeDevice(desc))) {
clearAudioSourcesForOutput(output);
closeOutput(output);
}
@@ -353,6 +359,8 @@
cleanUpForDevice(device);
}
+ checkLeBroadcastRoutes(wasLeUnicastActive, nullptr, 0);
+
mpClientInterface->onAudioPortListUpdate();
return NO_ERROR;
} // end if is output device
@@ -801,6 +809,7 @@
ALOGV("setPhoneState() state %d", state);
// store previous phone state for management of sonification strategy below
int oldState = mEngine->getPhoneState();
+ bool wasLeUnicastActive = isLeUnicastActive();
if (mEngine->setPhoneState(state) != NO_ERROR) {
ALOGW("setPhoneState() invalid or same state %d", state);
@@ -879,6 +888,8 @@
}
}
+ checkLeBroadcastRoutes(wasLeUnicastActive, nullptr, delayMs);
+
if (isStateInCall(state)) {
ALOGV("setPhoneState() in call state management: new state is %d", state);
// force reevaluating accessibility routing when call starts
@@ -1493,8 +1504,7 @@
*isSpatialized = false;
if (mSpatializerOutput != nullptr
- && canBeSpatializedInt(attr, config,
- devices.toTypeAddrVector(), false /* allowCurrentOutputReconfig */)) {
+ && canBeSpatializedInt(attr, config, devices.toTypeAddrVector())) {
*isSpatialized = true;
return mSpatializerOutput->mIoHandle;
}
@@ -1986,6 +1996,22 @@
return status;
}
+bool AudioPolicyManager::isLeUnicastActive() const {
+ if (isInCall()) {
+ return true;
+ }
+ return isAnyDeviceTypeActive(getAudioDeviceOutLeAudioUnicastSet());
+}
+
+bool AudioPolicyManager::isAnyDeviceTypeActive(const DeviceTypeSet& deviceTypes) const {
+ if (mAvailableOutputDevices.getDevicesFromTypes(deviceTypes).isEmpty()) {
+ return false;
+ }
+ bool active = mOutputs.isAnyDeviceTypeActive(deviceTypes);
+ ALOGV("%s active %d", __func__, active);
+ return active;
+}
+
status_t AudioPolicyManager::startSource(const sp<SwAudioOutputDescriptor>& outputDesc,
const sp<TrackClientDescriptor>& client,
uint32_t *delayMs)
@@ -2037,6 +2063,7 @@
// and muting would result in unnecessary delay and dropped audio.
const uint32_t outputLatencyMs = outputDesc->latency();
bool requiresMuteCheck = outputDesc->isActive(outputLatencyMs * 2); // account for drain
+ bool wasLeUnicastActive = isLeUnicastActive();
// increment usage count for this stream on the requested output:
// NOTE that the usage count is the same for duplicated output and hardware output which is
@@ -2115,11 +2142,15 @@
// apply volume rules for current stream and device if necessary
auto &curves = getVolumeCurves(client->attributes());
- checkAndSetVolume(curves, client->volumeSource(),
+ if (NO_ERROR != checkAndSetVolume(curves, client->volumeSource(),
curves.getVolumeIndex(outputDesc->devices().types()),
outputDesc,
outputDesc->devices().types(), 0 /*delay*/,
- outputDesc->useHwGain() /*force*/);
+ outputDesc->useHwGain() /*force*/)) {
+ // request AudioService to reinitialize the volume curves asynchronously
+ ALOGE("checkAndSetVolume failed, requesting volume range init");
+ mpClientInterface->onVolumeRangeInitRequest();
+ };
// update the outputs if starting an output with a stream that can affect notification
// routing
@@ -2160,9 +2191,38 @@
AUDIO_FORMAT_DEFAULT);
}
+ checkLeBroadcastRoutes(wasLeUnicastActive, outputDesc, *delayMs);
+
return NO_ERROR;
}
+void AudioPolicyManager::checkLeBroadcastRoutes(bool wasUnicastActive,
+ sp<SwAudioOutputDescriptor> ignoredOutput, uint32_t delayMs) {
+ bool isUnicastActive = isLeUnicastActive();
+
+ if (wasUnicastActive != isUnicastActive) {
+ //reroute all outputs routed to LE broadcast if LE unicast activy changed on any output
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
+ if (desc != ignoredOutput && desc->isActive()
+ && ((isUnicastActive &&
+ !desc->devices().
+ getDevicesFromType(AUDIO_DEVICE_OUT_BLE_BROADCAST).isEmpty())
+ || (wasUnicastActive &&
+ !desc->devices().getDevicesFromTypes(
+ getAudioDeviceOutLeAudioUnicastSet()).isEmpty()))) {
+ DeviceVector newDevices = getNewOutputDevices(desc, false /*fromCache*/);
+ bool force = desc->devices() != newDevices;
+ setOutputDevices(desc, newDevices, force, delayMs);
+ // re-apply device specific volume if not done by setOutputDevice()
+ if (!force) {
+ applyStreamVolumes(desc, newDevices.types(), delayMs);
+ }
+ }
+ }
+ }
+}
+
status_t AudioPolicyManager::stopOutput(audio_port_handle_t portId)
{
ALOGV("%s portId %d", __FUNCTION__, portId);
@@ -2191,6 +2251,7 @@
// always handle stream stop, check which stream type is stopping
audio_stream_type_t stream = client->stream();
auto clientVolSrc = client->volumeSource();
+ bool wasLeUnicastActive = isLeUnicastActive();
handleEventForBeacon(stream == AUDIO_STREAM_TTS ? STOPPING_BEACON : STOPPING_OUTPUT);
@@ -2269,6 +2330,9 @@
if (followsSameRouting(client->attributes(), attributes_initializer(AUDIO_USAGE_MEDIA))) {
selectOutputForMusicEffects();
}
+
+ checkLeBroadcastRoutes(wasLeUnicastActive, outputDesc, outputDesc->latency()*2);
+
return NO_ERROR;
} else {
ALOGW("stopOutput() refcount is already 0");
@@ -2344,7 +2408,6 @@
session, flags, toString(*attr).c_str(), *selectedDeviceId);
status_t status = NO_ERROR;
- audio_source_t halInputSource;
audio_attributes_t attributes = *attr;
sp<AudioPolicyMix> policyMix;
sp<DeviceDescriptor> device;
@@ -2415,8 +2478,6 @@
*input = AUDIO_IO_HANDLE_NONE;
*inputType = API_INPUT_INVALID;
- halInputSource = attributes.source;
-
if (attributes.source == AUDIO_SOURCE_REMOTE_SUBMIX &&
strncmp(attributes.tags, "addr=", strlen("addr=")) == 0) {
status = mPolicyMixes.getInputMixForAttr(attributes, &policyMix);
@@ -3578,6 +3639,7 @@
void AudioPolicyManager::updateCallAndOutputRouting(bool forceVolumeReeval, uint32_t delayMs)
{
uint32_t waitMs = 0;
+ bool wasLeUnicastActive = isLeUnicastActive();
if (updateCallRouting(true /*fromCache*/, delayMs, &waitMs) == NO_ERROR) {
// Only apply special touch sound delay once
delayMs = 0;
@@ -3601,6 +3663,7 @@
applyStreamVolumes(outputDesc, newDevices.types(), waitMs, true);
}
}
+ checkLeBroadcastRoutes(wasLeUnicastActive, nullptr, delayMs);
}
void AudioPolicyManager::updateInputRouting() {
@@ -5273,25 +5336,9 @@
return source;
}
-/* static */
-bool AudioPolicyManager::isChannelMaskSpatialized(audio_channel_mask_t channels) {
- switch (channels) {
- case AUDIO_CHANNEL_OUT_5POINT1:
- case AUDIO_CHANNEL_OUT_5POINT1POINT2:
- case AUDIO_CHANNEL_OUT_5POINT1POINT4:
- case AUDIO_CHANNEL_OUT_7POINT1:
- case AUDIO_CHANNEL_OUT_7POINT1POINT2:
- case AUDIO_CHANNEL_OUT_7POINT1POINT4:
- return true;
- default:
- return false;
- }
-}
-
bool AudioPolicyManager::canBeSpatializedInt(const audio_attributes_t *attr,
const audio_config_t *config,
- const AudioDeviceTypeAddrVector &devices,
- bool allowCurrentOutputReconfig) const
+ const AudioDeviceTypeAddrVector &devices) const
{
// The caller can have the audio attributes criteria ignored by either passing a null ptr or
// the AUDIO_ATTRIBUTES_INITIALIZER value.
@@ -5320,20 +5367,11 @@
// the AUDIO_CONFIG_INITIALIZER value.
// If an audio config is specified, current policy is to only allow spatialization for
// some positional channel masks.
- // If the spatializer output is already opened, only channel masks included in the
- // spatializer output mixer channel mask are allowed.
if (config != nullptr && *config != AUDIO_CONFIG_INITIALIZER) {
- if (!isChannelMaskSpatialized(config->channel_mask)) {
+ if (!audio_is_channel_mask_spatialized(config->channel_mask)) {
return false;
}
- if (!allowCurrentOutputReconfig && mSpatializerOutput != nullptr
- && mSpatializerOutput->mProfile == profile) {
- if ((config->channel_mask & mSpatializerOutput->mMixerChannelMask)
- != config->channel_mask) {
- return false;
- }
- }
}
return true;
}
@@ -5349,8 +5387,7 @@
audio_config_base_t clientConfig = client->config();
audio_config_t config = audio_config_initializer(&clientConfig);
if (desc != mSpatializerOutput
- && canBeSpatializedInt(&attr, &config,
- devicesTypeAddress, false /* allowCurrentOutputReconfig */)) {
+ && canBeSpatializedInt(&attr, &config, devicesTypeAddress)) {
streamsToInvalidate.insert(client->stream());
}
}
@@ -5361,6 +5398,29 @@
}
}
+
+bool AudioPolicyManager::isOutputOnlyAvailableRouteToSomeDevice(
+ const sp<SwAudioOutputDescriptor>& outputDesc) {
+ if (outputDesc->isDuplicated()) {
+ return false;
+ }
+ DeviceVector devices = outputDesc->supportedDevices();
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
+ if (desc == outputDesc || desc->isDuplicated()) {
+ continue;
+ }
+ DeviceVector sharedDevices = desc->filterSupportedDevices(devices);
+ if (!sharedDevices.isEmpty()
+ && (desc->devicesSupportEncodedFormats(sharedDevices.types())
+ == outputDesc->devicesSupportEncodedFormats(sharedDevices.types()))) {
+ return false;
+ }
+ }
+ return true;
+}
+
+
status_t AudioPolicyManager::getSpatializerOutput(const audio_config_base_t *mixerConfig,
const audio_attributes_t *attr,
audio_io_handle_t *output) {
@@ -5374,82 +5434,68 @@
config = audio_config_initializer(mixerConfig);
configPtr = &config;
}
- if (!canBeSpatializedInt(
- attr, configPtr, devicesTypeAddress)) {
- ALOGW("%s provided attributes or mixer config cannot be spatialized", __func__);
+ if (!canBeSpatializedInt(attr, configPtr, devicesTypeAddress)) {
+ ALOGV("%s provided attributes or mixer config cannot be spatialized", __func__);
return BAD_VALUE;
}
sp<IOProfile> profile =
getSpatializerOutputProfile(configPtr, devicesTypeAddress);
if (profile == nullptr) {
- ALOGW("%s no suitable output profile for provided attributes or mixer config", __func__);
+ ALOGV("%s no suitable output profile for provided attributes or mixer config", __func__);
return BAD_VALUE;
}
- if (mSpatializerOutput != nullptr && mSpatializerOutput->mProfile == profile
- && configPtr != nullptr
- && configPtr->channel_mask == mSpatializerOutput->mMixerChannelMask) {
- *output = mSpatializerOutput->mIoHandle;
- ALOGV("%s returns current spatializer output %d", __func__, *output);
- return NO_ERROR;
- }
- mSpatializerOutput.clear();
+ std::vector<sp<SwAudioOutputDescriptor>> spatializerOutputs;
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;
+ if (!desc->isDuplicated()
+ && (desc->mFlags & AUDIO_OUTPUT_FLAG_SPATIALIZER) != 0) {
+ spatializerOutputs.push_back(desc);
+ ALOGV("%s adding opened spatializer Output %d", __func__, desc->mIoHandle);
}
}
- if (mSpatializerOutput == nullptr) {
- ALOGW("%s no opened spatializer output for profile %s",
- __func__, profile->getName().c_str());
- return BAD_VALUE;
+ mSpatializerOutput.clear();
+ bool outputsChanged = false;
+ for (const auto& desc : spatializerOutputs) {
+ if (desc->mProfile == profile
+ && (configPtr == nullptr
+ || configPtr->channel_mask == desc->mMixerChannelMask)) {
+ mSpatializerOutput = desc;
+ ALOGV("%s reusing current spatializer output %d", __func__, desc->mIoHandle);
+ } else {
+ ALOGV("%s closing spatializerOutput output %d to match channel mask %#x"
+ " and devices %s", __func__, desc->mIoHandle,
+ configPtr != nullptr ? configPtr->channel_mask : 0,
+ devices.toString().c_str());
+ closeOutput(desc->mIoHandle);
+ outputsChanged = true;
+ }
}
- if (configPtr != nullptr
- && configPtr->channel_mask != mSpatializerOutput->mMixerChannelMask) {
- audio_config_base_t savedMixerConfig = {
- .sample_rate = mSpatializerOutput->getSamplingRate(),
- .format = mSpatializerOutput->getFormat(),
- .channel_mask = mSpatializerOutput->mMixerChannelMask,
- };
- DeviceVector savedDevices = mSpatializerOutput->devices();
-
- ALOGV("%s reopening spatializer output to match channel mask %#x (current mask %#x)",
- __func__, configPtr->channel_mask, mSpatializerOutput->mMixerChannelMask);
-
- closeOutput(mSpatializerOutput->mIoHandle);
- //from now on mSpatializerOutput is null
-
+ if (mSpatializerOutput == nullptr) {
sp<SwAudioOutputDescriptor> desc =
openOutputWithProfileAndDevice(profile, devices, mixerConfig);
- if (desc == nullptr) {
- // re open the spatializer output with previous channel mask
- desc = openOutputWithProfileAndDevice(profile, savedDevices, &savedMixerConfig);
- if (desc == nullptr) {
- ALOGE("%s failed to restore mSpatializerOutput with previous config", __func__);
- } else {
- mSpatializerOutput = desc;
- }
- mPreviousOutputs = mOutputs;
- mpClientInterface->onAudioPortListUpdate();
- *output = AUDIO_IO_HANDLE_NONE;
- ALOGW("%s could not open spatializer output with requested config", __func__);
- return BAD_VALUE;
+ if (desc != nullptr) {
+ mSpatializerOutput = desc;
+ outputsChanged = true;
}
- mSpatializerOutput = desc;
- mPreviousOutputs = mOutputs;
- mpClientInterface->onAudioPortListUpdate();
}
checkVirtualizerClientRoutes();
+ if (outputsChanged) {
+ mPreviousOutputs = mOutputs;
+ mpClientInterface->onAudioPortListUpdate();
+ }
+
+ if (mSpatializerOutput == nullptr) {
+ ALOGV("%s could not open spatializer output with requested config", __func__);
+ return BAD_VALUE;
+ }
*output = mSpatializerOutput->mIoHandle;
- ALOGV("%s returns new spatializer output %d", __func__, *output);
- return NO_ERROR;
+ ALOGV("%s returning new spatializer output %d", __func__, *output);
+ return OK;
}
status_t AudioPolicyManager::releaseSpatializerOutput(audio_io_handle_t output) {
@@ -5460,9 +5506,12 @@
return BAD_VALUE;
}
- mSpatializerOutput.clear();
-
- checkVirtualizerClientRoutes();
+ if (!isOutputOnlyAvailableRouteToSomeDevice(mSpatializerOutput)) {
+ ALOGV("%s closing spatializer output %d", __func__, mSpatializerOutput->mIoHandle);
+ closeOutput(mSpatializerOutput->mIoHandle);
+ //from now on mSpatializerOutput is null
+ checkVirtualizerClientRoutes();
+ }
return NO_ERROR;
}
@@ -5539,6 +5588,7 @@
return status;
}
+ mEngine->updateDeviceSelectionCache();
mCommunnicationStrategy = mEngine->getProductStrategyForAttributes(
mEngine->getAttributesForStreamType(AUDIO_STREAM_VOICE_CALL));
@@ -5738,6 +5788,21 @@
inputDesc->close();
}
}
+
+ // Check if spatializer outputs can be closed until used.
+ // mOutputs vector never contains duplicated outputs at this point.
+ std::vector<audio_io_handle_t> outputsClosed;
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
+ if ((desc->mFlags & AUDIO_OUTPUT_FLAG_SPATIALIZER) != 0
+ && !isOutputOnlyAvailableRouteToSomeDevice(desc)) {
+ outputsClosed.push_back(desc->mIoHandle);
+ desc->close();
+ }
+ }
+ for (auto output : outputsClosed) {
+ removeOutput(output);
+ }
}
void AudioPolicyManager::addOutput(audio_io_handle_t output,
@@ -6432,6 +6497,18 @@
return false;
}
+bool AudioPolicyManager::isHearingAidUsedForComm() const {
+ DeviceVector devices = mEngine->getOutputDevicesForStream(AUDIO_STREAM_VOICE_CALL,
+ true /*fromCache*/);
+ for (const auto &device : devices) {
+ if (device->type() == AUDIO_DEVICE_OUT_HEARING_AID) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
void AudioPolicyManager::checkA2dpSuspend()
{
audio_io_handle_t a2dpOutput = mOutputs.getA2dpOutput();
@@ -7229,13 +7306,15 @@
bool isBtScoVolSrc = (volumeSource != VOLUME_SOURCE_NONE) && (btScoVolSrc == volumeSource);
bool isScoRequested = isScoRequestedForComm();
+ bool isHAUsed = isHearingAidUsedForComm();
+
// do not change in call volume if bluetooth is connected and vice versa
// if sco and call follow same curves, bypass forceUseForComm
if ((callVolSrc != btScoVolSrc) &&
((isVoiceVolSrc && isScoRequested) ||
- (isBtScoVolSrc && !isScoRequested))) {
+ (isBtScoVolSrc && !(isScoRequested || isHAUsed)))) {
ALOGV("%s cannot set volume group %d volume when is%srequested for comm", __func__,
- volumeSource, isScoRequested ? " " : "n ot ");
+ volumeSource, isScoRequested ? " " : " not ");
// Do not return an error here as AudioService will always set both voice call
// and bluetooth SCO volumes due to stream aliasing.
return NO_ERROR;
@@ -7244,6 +7323,11 @@
deviceTypes = outputDesc->devices().types();
}
+ if (curves.getVolumeIndexMin() < 0 || curves.getVolumeIndexMax() < 0) {
+ ALOGE("invalid volume index range");
+ return BAD_VALUE;
+ }
+
float volumeDb = computeVolume(curves, volumeSource, index, deviceTypes);
if (outputDesc->isFixedVolume(deviceTypes) ||
// Force VoIP volume to max for bluetooth SCO device except if muted
@@ -7388,13 +7472,11 @@
return mEngine->getForceUse(usage);
}
-bool AudioPolicyManager::isInCall()
-{
+bool AudioPolicyManager::isInCall() const {
return isStateInCall(mEngine->getPhoneState());
}
-bool AudioPolicyManager::isStateInCall(int state)
-{
+bool AudioPolicyManager::isStateInCall(int state) const {
return is_state_in_call(state);
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index b12b71a..db0ee15 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -598,9 +598,9 @@
audio_mode_t getPhoneState();
// true if device is in a telephony or VoIP call
- virtual bool isInCall();
+ virtual bool isInCall() const;
// true if given state represents a device in a telephony or VoIP call
- virtual bool isStateInCall(int state);
+ virtual bool isStateInCall(int state) const;
// true if playback to call TX or capture from call RX is possible
bool isCallAudioAccessible();
@@ -887,6 +887,21 @@
void closeActiveClients(const sp<AudioInputDescriptor>& input);
void closeClient(audio_port_handle_t portId);
+ /**
+ * @brief isAnyDeviceTypeActive: returns true if at least one active client is routed to
+ * one of the specified devices
+ * @param deviceTypes list of devices to consider
+ */
+ bool isAnyDeviceTypeActive(const DeviceTypeSet& deviceTypes) const;
+ /**
+ * @brief isLeUnicastActive: returns true if a call is active or at least one active client
+ * is routed to a LE unicast device
+ */
+ bool isLeUnicastActive() const;
+
+ void checkLeBroadcastRoutes(bool wasUnicastActive,
+ sp<SwAudioOutputDescriptor> ignoredOutput, uint32_t delayMs);
+
const uid_t mUidCached; // AID_AUDIOSERVER
AudioPolicyClientInterface *mpClientInterface; // audio policy client interface
sp<SwAudioOutputDescriptor> mPrimaryOutput; // primary output descriptor
@@ -1078,25 +1093,28 @@
* @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;
+ const AudioDeviceTypeAddrVector &devices) const;
sp<IOProfile> getSpatializerOutputProfile(const audio_config_t *config,
const AudioDeviceTypeAddrVector &devices) const;
- static bool isChannelMaskSpatialized(audio_channel_mask_t channels);
-
void checkVirtualizerClientRoutes();
/**
+ * @brief Returns true if at least one device can only be reached via the output passed
+ * as argument. Always returns false for duplicated outputs.
+ * This can be used to decide if an output can be closed without forbidding
+ * playback to any given device.
+ * @param outputDesc the output to consider
+ * @return true if at least one device can only be reached via the output.
+ */
+ bool isOutputOnlyAvailableRouteToSomeDevice(const sp<SwAudioOutputDescriptor>& outputDesc);
+
+ /**
* @brief getInputForDevice selects an input handle for a given input device and
* requester context
* @param device to be used by requester, selected by policy mix rules or engine
@@ -1189,6 +1207,8 @@
bool isScoRequestedForComm() const;
+ bool isHearingAidUsedForComm() const;
+
bool areAllActiveTracksRerouted(const sp<SwAudioOutputDescriptor>& output);
/**
diff --git a/services/audiopolicy/service/AudioPolicyClientImpl.cpp b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
index 63a1e71..c766a15 100644
--- a/services/audiopolicy/service/AudioPolicyClientImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
@@ -277,6 +277,11 @@
mAudioPolicyService->onRoutingUpdated();
}
+void AudioPolicyService::AudioPolicyClient::onVolumeRangeInitRequest()
+{
+ mAudioPolicyService->onVolumeRangeInitRequest();
+}
+
audio_unique_id_t AudioPolicyService::AudioPolicyClient::newAudioUniqueId(audio_unique_id_use_t use)
{
return AudioSystem::newAudioUniqueId(use);
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index da0a4a9..e7d945f 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -488,6 +488,19 @@
}
}
+void AudioPolicyService::onVolumeRangeInitRequest()
+{
+ mOutputCommandThread->volRangeInitReqCommand();
+}
+
+void AudioPolicyService::doOnVolumeRangeInitRequest()
+{
+ Mutex::Autolock _l(mNotificationClientsLock);
+ for (size_t i = 0; i < mNotificationClients.size(); i++) {
+ mNotificationClients.valueAt(i)->onVolumeRangeInitRequest();
+ }
+}
+
void AudioPolicyService::onCheckSpatializer()
{
Mutex::Autolock _l(mLock);
@@ -721,6 +734,13 @@
}
}
+void AudioPolicyService::NotificationClient::onVolumeRangeInitRequest()
+{
+ if (mAudioPolicyServiceClient != 0 && isServiceUid(mUid)) {
+ mAudioPolicyServiceClient->onVolumeRangeInitRequest();
+ }
+}
+
void AudioPolicyService::binderDied(const wp<IBinder>& who) {
ALOGW("binderDied() %p, calling pid %d", who.unsafe_get(),
IPCThreadState::self()->getCallingPid());
@@ -1938,12 +1958,16 @@
while (!exitPending())
{
sp<AudioPolicyService> svc;
+ int numTimesBecameEmpty = 0;
while (!mAudioCommands.isEmpty() && !exitPending()) {
nsecs_t curTime = systemTime();
// commands are sorted by increasing time stamp: execute them from index 0 and up
if (mAudioCommands[0]->mTime <= curTime) {
sp<AudioCommand> command = mAudioCommands[0];
mAudioCommands.removeAt(0);
+ if (mAudioCommands.isEmpty()) {
+ ++numTimesBecameEmpty;
+ }
mLastCommand = command;
switch (command->mCommand) {
@@ -2157,6 +2181,17 @@
mLock.lock();
} break;
+ case VOL_RANGE_INIT_REQUEST: {
+ ALOGV("AudioCommandThread() processing volume range init request");
+ svc = mService.promote();
+ if (svc == 0) {
+ break;
+ }
+ mLock.unlock();
+ svc->doOnVolumeRangeInitRequest();
+ mLock.lock();
+ } break;
+
default:
ALOGW("AudioCommandThread() unknown command %d", command->mCommand);
}
@@ -2180,8 +2215,9 @@
}
}
- // release delayed commands wake lock if the queue is empty
- if (mAudioCommands.isEmpty()) {
+ // release delayed commands wake lock as many times as we made the queue is
+ // empty during popping.
+ while (numTimesBecameEmpty--) {
release_wake_lock(mName.string());
}
@@ -2480,6 +2516,14 @@
sendCommand(command);
}
+void AudioPolicyService::AudioCommandThread::volRangeInitReqCommand()
+{
+ sp<AudioCommand>command = new AudioCommand();
+ command->mCommand = VOL_RANGE_INIT_REQUEST;
+ ALOGV("AudioCommandThread() adding volume range init request");
+ sendCommand(command);
+}
+
status_t AudioPolicyService::AudioCommandThread::sendCommand(sp<AudioCommand>& command, int delayMs)
{
{
@@ -2647,6 +2691,10 @@
} break;
+ case VOL_RANGE_INIT_REQUEST: {
+ // command may come from different requests, do not filter
+ } break;
+
default:
break;
}
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index d863ff1..3a08cf8 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -343,6 +343,9 @@
void onRoutingUpdated();
void doOnRoutingUpdated();
+ void onVolumeRangeInitRequest();
+ void doOnVolumeRangeInitRequest();
+
/**
* Spatializer SpatializerPolicyCallback implementation.
* onCheckSpatializer() sends an event on mOutputCommandThread which executes
@@ -530,7 +533,8 @@
ROUTING_UPDATED,
UPDATE_UID_STATES,
CHECK_SPATIALIZER_OUTPUT, // verify if spatializer effect should be created or moved
- UPDATE_ACTIVE_SPATIALIZER_TRACKS // Update active track counts on spalializer output
+ UPDATE_ACTIVE_SPATIALIZER_TRACKS, // Update active track counts on spalializer output
+ VOL_RANGE_INIT_REQUEST, // request to reset the volume range indices
};
AudioCommandThread (String8 name, const wp<AudioPolicyService>& service);
@@ -581,6 +585,7 @@
void updateUidStatesCommand();
void checkSpatializerCommand();
void updateActiveSpatializerTracksCommand();
+ void volRangeInitReqCommand();
void insertCommand_l(AudioCommand *command, int delayMs = 0);
private:
@@ -803,6 +808,8 @@
virtual void onRoutingUpdated();
+ virtual void onVolumeRangeInitRequest();
+
virtual audio_unique_id_t newAudioUniqueId(audio_unique_id_use_t use);
void setSoundTriggerCaptureState(bool active) override;
@@ -842,6 +849,7 @@
audio_patch_handle_t patchHandle,
audio_source_t source);
void onRoutingUpdated();
+ void onVolumeRangeInitRequest();
void setAudioPortCallbacksEnabled(bool enabled);
void setAudioVolumeGroupCallbacksEnabled(bool enabled);
diff --git a/services/audiopolicy/service/Spatializer.cpp b/services/audiopolicy/service/Spatializer.cpp
index 3b466d7..ef11072 100644
--- a/services/audiopolicy/service/Spatializer.cpp
+++ b/services/audiopolicy/service/Spatializer.cpp
@@ -342,12 +342,7 @@
modes->push_back(SpatializerHeadTrackingMode::DISABLED);
if (mSupportsHeadTracking) {
- if (mHeadSensor != SpatializerPoseController::INVALID_SENSOR) {
- modes->push_back(SpatializerHeadTrackingMode::RELATIVE_WORLD);
- if (mScreenSensor != SpatializerPoseController::INVALID_SENSOR) {
- modes->push_back(SpatializerHeadTrackingMode::RELATIVE_SCREEN);
- }
- }
+ modes->push_back(SpatializerHeadTrackingMode::RELATIVE_WORLD);
}
return Status::ok();
}
@@ -459,9 +454,7 @@
}
std::lock_guard lock(mLock);
mScreenSensor = sensorHandle;
- if (mPoseController != nullptr) {
- mPoseController->setScreenSensor(mScreenSensor);
- }
+ checkSensorsState_l();
return Status::ok();
}
@@ -569,9 +562,6 @@
sp<media::ISpatializerHeadTrackingCallback> callback;
{
std::lock_guard lock(mLock);
- if (mActualHeadTrackingMode == SpatializerHeadTrackingMode::DISABLED) {
- return;
- }
callback = mHeadTrackingCallback;
if (mEngine != nullptr) {
setEffectParameter_l(SPATIALIZER_PARAM_HEAD_TO_STAGE, headToStage);
@@ -595,7 +585,6 @@
ALOGV("%s(%d)", __func__, (int) mode);
sp<media::ISpatializerHeadTrackingCallback> callback;
SpatializerHeadTrackingMode spatializerMode;
- bool modeChanged = false;
{
std::lock_guard lock(mLock);
if (!mSupportsHeadTracking) {
@@ -615,21 +604,19 @@
LOG_ALWAYS_FATAL("Unknown mode: %d", mode);
}
}
- modeChanged = mActualHeadTrackingMode != spatializerMode;
mActualHeadTrackingMode = spatializerMode;
- if (modeChanged && mEngine != nullptr) {
+ if (mEngine != nullptr) {
setEffectParameter_l(SPATIALIZER_PARAM_HEADTRACKING_MODE,
std::vector<SpatializerHeadTrackingMode>{spatializerMode});
}
callback = mHeadTrackingCallback;
}
- if (callback != nullptr && modeChanged) {
+ if (callback != nullptr) {
callback->onHeadTrackingModeChanged(spatializerMode);
}
}
status_t Spatializer::attachOutput(audio_io_handle_t output, size_t numActiveTracks) {
- std::shared_ptr<SpatializerPoseController> poseController;
bool outputChanged = false;
sp<media::INativeSpatializerCallback> callback;
@@ -663,14 +650,9 @@
if (mSupportsHeadTracking) {
checkPoseController_l();
checkSensorsState_l();
- poseController = mPoseController;
}
callback = mSpatializerCallback;
}
- if (poseController != nullptr) {
- poseController->calculateAsync();
- poseController->waitUntilCalculated();
- }
if (outputChanged && callback != nullptr) {
callback->onOutputChanged(output);
@@ -750,7 +732,7 @@
if (isControllerNeeded && mPoseController == nullptr) {
mPoseController = std::make_shared<SpatializerPoseController>(
static_cast<SpatializerPoseController::Listener*>(this),
- 10ms, std::chrono::microseconds::max());
+ 10ms, std::nullopt);
LOG_ALWAYS_FATAL_IF(mPoseController == nullptr,
"%s could not allocate pose controller", __func__);
mPoseController->setDisplayOrientation(mDisplayOrientation);
diff --git a/services/audiopolicy/service/SpatializerPoseController.cpp b/services/audiopolicy/service/SpatializerPoseController.cpp
index 58a57ac..0a9f4d9 100644
--- a/services/audiopolicy/service/SpatializerPoseController.cpp
+++ b/services/audiopolicy/service/SpatializerPoseController.cpp
@@ -46,9 +46,8 @@
// high will result in high prediction errors whenever the head accelerates (changes velocity).
constexpr auto kPredictionDuration = 50ms;
-// After losing this many consecutive samples from either sensor, we would treat the measurement as
-// stale;
-constexpr auto kMaxLostSamples = 4;
+// After not getting a pose sample for this long, we would treat the measurement as stale.
+constexpr auto kFreshnessTimeout = 50ms;
// Auto-recenter kicks in after the head has been still for this long.
constexpr auto kAutoRecenterWindowDuration = 6s;
@@ -79,14 +78,14 @@
} // namespace
SpatializerPoseController::SpatializerPoseController(Listener* listener,
- std::chrono::microseconds sensorPeriod,
- std::chrono::microseconds maxUpdatePeriod)
+ std::chrono::microseconds sensorPeriod,
+ std::optional<std::chrono::microseconds> maxUpdatePeriod)
: mListener(listener),
mSensorPeriod(sensorPeriod),
mProcessor(createHeadTrackingProcessor(HeadTrackingProcessor::Options{
.maxTranslationalVelocity = kMaxTranslationalVelocity / kTicksPerSecond,
.maxRotationalVelocity = kMaxRotationalVelocity / kTicksPerSecond,
- .freshnessTimeout = Ticks(sensorPeriod * kMaxLostSamples).count(),
+ .freshnessTimeout = Ticks(kFreshnessTimeout).count(),
.predictionDuration = Ticks(kPredictionDuration).count(),
.autoRecenterWindowDuration = Ticks(kAutoRecenterWindowDuration).count(),
.autoRecenterTranslationalThreshold = kAutoRecenterTranslationThreshold,
@@ -102,8 +101,12 @@
std::optional<HeadTrackingMode> modeIfChanged;
{
std::unique_lock lock(mMutex);
- mCondVar.wait_for(lock, maxUpdatePeriod,
- [this] { return mShouldExit || mShouldCalculate; });
+ if (maxUpdatePeriod.has_value()) {
+ mCondVar.wait_for(lock, maxUpdatePeriod.value(),
+ [this] { return mShouldExit || mShouldCalculate; });
+ } else {
+ mCondVar.wait(lock, [this] { return mShouldExit || mShouldCalculate; });
+ }
if (mShouldExit) {
ALOGV("Exiting thread");
return;
diff --git a/services/audiopolicy/service/SpatializerPoseController.h b/services/audiopolicy/service/SpatializerPoseController.h
index 2b5c189..2c6d79a 100644
--- a/services/audiopolicy/service/SpatializerPoseController.h
+++ b/services/audiopolicy/service/SpatializerPoseController.h
@@ -60,10 +60,10 @@
* Ctor.
* sensorPeriod determines how often to receive updates from the sensors (input rate).
* maxUpdatePeriod determines how often to produce an output when calculateAsync() isn't
- * invoked.
+ * invoked; passing nullopt means an output is never produced.
*/
SpatializerPoseController(Listener* listener, std::chrono::microseconds sensorPeriod,
- std::chrono::microseconds maxUpdatePeriod);
+ std::optional<std::chrono::microseconds> maxUpdatePeriod);
/** Dtor. */
~SpatializerPoseController();
diff --git a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
index adef8f1..057fa58 100644
--- a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
@@ -138,7 +138,12 @@
}
size_t getRoutingUpdatedCounter() const {
- return mRoutingUpdatedUpdateCount; }
+ return mRoutingUpdatedUpdateCount;
+ }
+
+ void onVolumeRangeInitRequest() override {
+
+ }
status_t updateSecondaryOutputs(
const TrackSecondaryOutputsMap& trackSecondaryOutputs __unused) override {
diff --git a/services/audiopolicy/tests/AudioPolicyTestClient.h b/services/audiopolicy/tests/AudioPolicyTestClient.h
index da85658..8a85fee 100644
--- a/services/audiopolicy/tests/AudioPolicyTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyTestClient.h
@@ -85,6 +85,7 @@
audio_patch_handle_t patchHandle __unused,
audio_source_t source __unused) override { }
void onRoutingUpdated() override { }
+ void onVolumeRangeInitRequest() override { }
void setEffectSuspended(int effectId __unused,
audio_session_t sessionId __unused,
bool suspended __unused) {}
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp
index 1e2dccb..493696b 100644
--- a/services/camera/libcameraservice/Android.bp
+++ b/services/camera/libcameraservice/Android.bp
@@ -42,6 +42,7 @@
srcs: [
"CameraService.cpp",
+ "CameraServiceWatchdog.cpp",
"CameraFlashlight.cpp",
"common/Camera2ClientBase.cpp",
"common/CameraDeviceBase.cpp",
@@ -81,6 +82,7 @@
"device3/Camera3OutputUtils.cpp",
"device3/Camera3DeviceInjectionMethods.cpp",
"device3/UHRCropAndMeteringRegionMapper.cpp",
+ "device3/PreviewFrameSpacer.cpp",
"device3/hidl/HidlCamera3Device.cpp",
"device3/hidl/HidlCamera3OfflineSession.cpp",
"device3/hidl/HidlCamera3OutputUtils.cpp",
@@ -98,6 +100,7 @@
"utils/CameraTraces.cpp",
"utils/AutoConditionLock.cpp",
"utils/SessionConfigurationUtils.cpp",
+ "utils/SessionConfigurationUtilsHidl.cpp",
"utils/SessionStatsBuilder.cpp",
"utils/TagMonitor.cpp",
"utils/LatencyHistogram.cpp",
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 86e2ac2..3702812 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -1688,6 +1688,13 @@
return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, msg.string());
}
+ if (CameraServiceProxyWrapper::isCameraDisabled()) {
+ String8 msg =
+ String8::format("Camera disabled by device policy");
+ ALOGE("%s: %s", __FUNCTION__, msg.string());
+ return STATUS_ERROR(ERROR_DISABLED, msg.string());
+ }
+
// enforce system camera permissions
if (oomScoreOffset > 0 &&
!hasPermissionsForSystemCamera(callingPid, CameraThreadState::getCallingUid())) {
@@ -3716,21 +3723,10 @@
void CameraService::UidPolicy::onUidStateChanged(uid_t uid, int32_t procState,
int64_t procStateSeq __unused, int32_t capability __unused) {
- bool procStateChange = false;
- {
- Mutex::Autolock _l(mUidLock);
- if (mMonitoredUids.find(uid) != mMonitoredUids.end() &&
- mMonitoredUids[uid].procState != procState) {
- mMonitoredUids[uid].procState = procState;
- procStateChange = true;
- }
- }
-
- if (procStateChange) {
- sp<CameraService> service = mService.promote();
- if (service != nullptr) {
- service->notifyMonitoredUids();
- }
+ Mutex::Autolock _l(mUidLock);
+ if (mMonitoredUids.find(uid) != mMonitoredUids.end() &&
+ mMonitoredUids[uid].procState != procState) {
+ mMonitoredUids[uid].procState = procState;
}
}
diff --git a/services/camera/libcameraservice/CameraServiceWatchdog.cpp b/services/camera/libcameraservice/CameraServiceWatchdog.cpp
new file mode 100644
index 0000000..fcd6ebe
--- /dev/null
+++ b/services/camera/libcameraservice/CameraServiceWatchdog.cpp
@@ -0,0 +1,90 @@
+/*
+ * 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 "CameraServiceWatchdog"
+
+#include "CameraServiceWatchdog.h"
+
+namespace android {
+
+bool CameraServiceWatchdog::threadLoop()
+{
+ {
+ AutoMutex _l(mWatchdogLock);
+
+ while (mPause) {
+ mWatchdogCondition.wait(mWatchdogLock);
+ }
+ }
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(mCycleLengthMs));
+
+ {
+ AutoMutex _l(mWatchdogLock);
+
+ for (auto it = tidToCycleCounterMap.begin(); it != tidToCycleCounterMap.end(); it++) {
+ uint32_t currentThreadId = it->first;
+
+ tidToCycleCounterMap[currentThreadId]++;
+
+ if (tidToCycleCounterMap[currentThreadId] >= mMaxCycles) {
+ ALOGW("CameraServiceWatchdog triggering kill for pid: %d", getpid());
+ kill(getpid(), SIGKILL);
+ }
+ }
+ }
+
+ return true;
+}
+
+void CameraServiceWatchdog::requestExit()
+{
+ Thread::requestExit();
+
+ AutoMutex _l(mWatchdogLock);
+
+ tidToCycleCounterMap.clear();
+
+ if (mPause) {
+ mPause = false;
+ mWatchdogCondition.signal();
+ }
+}
+
+void CameraServiceWatchdog::stop(uint32_t tid)
+{
+ AutoMutex _l(mWatchdogLock);
+
+ tidToCycleCounterMap.erase(tid);
+
+ if (tidToCycleCounterMap.empty()) {
+ mPause = true;
+ }
+}
+
+void CameraServiceWatchdog::start(uint32_t tid)
+{
+ AutoMutex _l(mWatchdogLock);
+
+ tidToCycleCounterMap[tid] = 0;
+
+ if (mPause) {
+ mPause = false;
+ mWatchdogCondition.signal();
+ }
+}
+
+} // namespace android
diff --git a/services/camera/libcameraservice/CameraServiceWatchdog.h b/services/camera/libcameraservice/CameraServiceWatchdog.h
new file mode 100644
index 0000000..f4955e2
--- /dev/null
+++ b/services/camera/libcameraservice/CameraServiceWatchdog.h
@@ -0,0 +1,121 @@
+/*
+ * 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.
+ */
+
+/**
+ * The CameraService watchdog is used to help detect bad states in the
+ * Camera HAL. The threadloop uses cycle counters, assigned to each calling
+ * thread, to monitor the elapsing time and kills the process when the
+ * expected duration has exceeded.
+ * Notes on multi-threaded behaviors:
+ * - The threadloop is blocked/paused when there are no calls being
+ * monitored.
+ * - The start and stop functions handle simultaneous call monitoring
+ * and single call monitoring differently. See function documentation for
+ * more details.
+ */
+
+#include <chrono>
+#include <thread>
+#include <time.h>
+#include <utils/Thread.h>
+#include <utils/Log.h>
+#include <unordered_map>
+
+// Used to wrap the call of interest in start and stop calls
+#define WATCH(toMonitor) watchThread([&]() { return toMonitor;}, gettid())
+#define WATCH_CUSTOM_TIMER(toMonitor, cycles, cycleLength) \
+ watchThread([&]() { return toMonitor;}, gettid(), cycles, cycleLength);
+
+// Default cycles and cycle length values used to calculate permitted elapsed time
+const static size_t kMaxCycles = 100;
+const static uint32_t kCycleLengthMs = 100;
+
+namespace android {
+
+class CameraServiceWatchdog : public Thread {
+
+public:
+ explicit CameraServiceWatchdog() : mPause(true), mMaxCycles(kMaxCycles),
+ mCycleLengthMs(kCycleLengthMs) {};
+
+ explicit CameraServiceWatchdog (size_t maxCycles, uint32_t cycleLengthMs) :
+ mPause(true), mMaxCycles(maxCycles), mCycleLengthMs(cycleLengthMs) {};
+
+ virtual ~CameraServiceWatchdog() {};
+
+ virtual void requestExit();
+
+ /** Used to wrap monitored calls in start and stop functions using custom timer values */
+ template<typename T>
+ auto watchThread(T func, uint32_t tid, uint32_t cycles, uint32_t cycleLength) {
+ auto res = NULL;
+
+ if (cycles != mMaxCycles || cycleLength != mCycleLengthMs) {
+ // Create another instance of the watchdog to prevent disruption
+ // of timer for current monitored calls
+ sp<CameraServiceWatchdog> tempWatchdog =
+ new CameraServiceWatchdog(cycles, cycleLength);
+ tempWatchdog->run("CameraServiceWatchdog");
+ res = tempWatchdog->watchThread(func, tid);
+ tempWatchdog->requestExit();
+ tempWatchdog.clear();
+ } else {
+ // If custom timer values are equivalent to set class timer values, use
+ // current thread
+ res = watchThread(func, tid);
+ }
+
+ return res;
+ }
+
+ /** Used to wrap monitored calls in start and stop functions using class timer values */
+ template<typename T>
+ auto watchThread(T func, uint32_t tid) {
+ auto res = NULL;
+
+ start(tid);
+ res = func();
+ stop(tid);
+
+ return res;
+ }
+
+private:
+
+ /**
+ * Start adds a cycle counter for the calling thread. When threadloop is blocked/paused,
+ * start() unblocks and starts the watchdog
+ */
+ void start(uint32_t tid);
+
+ /**
+ * If there are no calls left to be monitored, stop blocks/pauses threadloop
+ * otherwise stop() erases the cycle counter to end watchdog for the calling thread
+ */
+ void stop(uint32_t tid);
+
+ virtual bool threadLoop();
+
+ Mutex mWatchdogLock; // Lock for condition variable
+ Condition mWatchdogCondition; // Condition variable for stop/start
+ bool mPause; // True if thread is currently paused
+ uint32_t mMaxCycles; // Max cycles
+ uint32_t mCycleLengthMs; // Length of time elapsed per cycle
+
+ std::unordered_map<uint32_t, uint32_t> tidToCycleCounterMap; // Thread Id to cycle counter map
+};
+
+} // namespace android
diff --git a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
index a38d7ae..467108d 100755
--- a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
@@ -20,6 +20,9 @@
#include <netinet/in.h>
+#include <aidl/android/hardware/camera/device/CameraBlob.h>
+#include <aidl/android/hardware/camera/device/CameraBlobId.h>
+
#include <binder/MemoryBase.h>
#include <binder/MemoryHeapBase.h>
#include <utils/Log.h>
@@ -36,6 +39,8 @@
namespace camera2 {
using android::camera3::CAMERA_STREAM_ROTATION_0;
+using aidl::android::hardware::camera::device::CameraBlob;
+using aidl::android::hardware::camera::device::CameraBlobId;
JpegProcessor::JpegProcessor(
sp<Camera2Client> client,
@@ -350,11 +355,11 @@
size_t size;
// First check for JPEG transport header at the end of the buffer
- uint8_t *header = jpegBuffer + (maxSize - sizeof(struct camera2_jpeg_blob));
- struct camera2_jpeg_blob *blob = (struct camera2_jpeg_blob*)(header);
- if (blob->jpeg_blob_id == CAMERA2_JPEG_BLOB_ID) {
- size = blob->jpeg_size;
- if (size > 0 && size <= maxSize - sizeof(struct camera2_jpeg_blob)) {
+ uint8_t *header = jpegBuffer + (maxSize - sizeof(CameraBlob));
+ CameraBlob *blob = (CameraBlob*)(header);
+ if (blob->blobId == CameraBlobId::JPEG) {
+ size = blob->blobSizeBytes;
+ if (size > 0 && size <= maxSize - sizeof(CameraBlob)) {
// Verify SOI and EOI markers
size_t offset = size - MARKER_LENGTH;
uint8_t *end = jpegBuffer + offset;
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 1f0e095..5db3fa6 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -721,8 +721,10 @@
}
*status = false;
+ camera3::metadataGetter getMetadata = [this](const String8 &id, bool /*overrideForPerfClass*/) {
+ return mDevice->infoPhysical(id);};
ret = mProviderManager->isSessionConfigurationSupported(mCameraIdStr.string(),
- sessionConfiguration, mOverrideForPerfClass, status);
+ sessionConfiguration, mOverrideForPerfClass, getMetadata, status);
switch (ret) {
case OK:
// Expected, do nothing.
diff --git a/services/camera/libcameraservice/api2/CompositeStream.h b/services/camera/libcameraservice/api2/CompositeStream.h
index d32b71c..600bd28 100644
--- a/services/camera/libcameraservice/api2/CompositeStream.h
+++ b/services/camera/libcameraservice/api2/CompositeStream.h
@@ -117,41 +117,6 @@
// Composite streams should behave accordingly.
void enableErrorState();
- // Utility class to lock and unlock a GraphicBuffer
- class GraphicBufferLocker {
- public:
- GraphicBufferLocker(sp<GraphicBuffer> buffer) : _buffer(buffer) {}
-
- status_t lockAsync(void** dstBuffer, int fenceFd) {
- if (_buffer == nullptr) return BAD_VALUE;
-
- status_t res = OK;
- if (!_locked) {
- status_t res = _buffer->lockAsync(GRALLOC_USAGE_SW_WRITE_OFTEN,
- dstBuffer, fenceFd);
- if (res == OK) {
- _locked = true;
- }
- }
- return res;
- }
-
- ~GraphicBufferLocker() {
- if (_locked && _buffer != nullptr) {
- auto res = _buffer->unlock();
- if (res != OK) {
- ALOGE("%s: Error trying to unlock buffer: %s (%d)", __FUNCTION__,
- strerror(-res), res);
- }
- }
- }
-
- private:
- sp<GraphicBuffer> _buffer;
- bool _locked = false;
- };
-
-
wp<CameraDeviceBase> mDevice;
wp<camera3::StatusTracker> mStatusTracker;
wp<hardware::camera2::ICameraDeviceCallbacks> mRemoteCallback;
diff --git a/services/camera/libcameraservice/api2/DepthCompositeStream.cpp b/services/camera/libcameraservice/api2/DepthCompositeStream.cpp
index aa057c7..048d85d 100644
--- a/services/camera/libcameraservice/api2/DepthCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/DepthCompositeStream.cpp
@@ -18,6 +18,9 @@
#define ATRACE_TAG ATRACE_TAG_CAMERA
//#define LOG_NDEBUG 0
+#include <aidl/android/hardware/camera/device/CameraBlob.h>
+#include <aidl/android/hardware/camera/device/CameraBlobId.h>
+
#include "api1/client2/JpegProcessor.h"
#include "common/CameraProviderManager.h"
#include "utils/SessionConfigurationUtils.h"
@@ -30,6 +33,9 @@
namespace android {
namespace camera3 {
+using aidl::android::hardware::camera::device::CameraBlob;
+using aidl::android::hardware::camera::device::CameraBlobId;
+
DepthCompositeStream::DepthCompositeStream(sp<CameraDeviceBase> device,
wp<hardware::camera2::ICameraDeviceCallbacks> cb) :
CompositeStream(device, cb),
@@ -367,7 +373,7 @@
return res;
}
- size_t finalJpegSize = actualJpegSize + sizeof(struct camera_jpeg_blob);
+ size_t finalJpegSize = actualJpegSize + sizeof(CameraBlob);
if (finalJpegSize > finalJpegBufferSize) {
ALOGE("%s: Final jpeg buffer not large enough for the jpeg blob header", __FUNCTION__);
outputANW->cancelBuffer(mOutputSurface.get(), anb, /*fence*/ -1);
@@ -383,10 +389,10 @@
ALOGV("%s: Final jpeg size: %zu", __func__, finalJpegSize);
uint8_t* header = static_cast<uint8_t *> (dstBuffer) +
- (gb->getWidth() - sizeof(struct camera_jpeg_blob));
- struct camera_jpeg_blob *blob = reinterpret_cast<struct camera_jpeg_blob*> (header);
- blob->jpeg_blob_id = CAMERA_JPEG_BLOB_ID;
- blob->jpeg_size = actualJpegSize;
+ (gb->getWidth() - sizeof(CameraBlob));
+ CameraBlob *blob = reinterpret_cast<CameraBlob*> (header);
+ blob->blobId = CameraBlobId::JPEG;
+ blob->blobSizeBytes = actualJpegSize;
outputANW->queueBuffer(mOutputSurface.get(), anb, /*fence*/ -1);
return res;
diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
index 6058429..54cc27a 100644
--- a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
@@ -23,7 +23,8 @@
#include <pthread.h>
#include <sys/syscall.h>
-#include <android/hardware/camera/device/3.5/types.h>
+#include <aidl/android/hardware/camera/device/CameraBlob.h>
+#include <aidl/android/hardware/camera/device/CameraBlobId.h>
#include <libyuv.h>
#include <gui/Surface.h>
#include <utils/Log.h>
@@ -41,8 +42,8 @@
#include "HeicEncoderInfoManager.h"
#include "HeicCompositeStream.h"
-using android::hardware::camera::device::V3_5::CameraBlob;
-using android::hardware::camera::device::V3_5::CameraBlobId;
+using aidl::android::hardware::camera::device::CameraBlob;
+using aidl::android::hardware::camera::device::CameraBlobId;
namespace android {
namespace camera3 {
@@ -441,6 +442,10 @@
newFormat->setInt32(KEY_TILE_HEIGHT, mGridHeight);
newFormat->setInt32(KEY_GRID_ROWS, mGridRows);
newFormat->setInt32(KEY_GRID_COLUMNS, mGridCols);
+ int32_t left, top, right, bottom;
+ if (newFormat->findRect("crop", &left, &top, &right, &bottom)) {
+ newFormat->setRect("crop", 0, 0, mOutputWidth - 1, mOutputHeight - 1);
+ }
}
}
newFormat->setInt32(KEY_IS_DEFAULT, 1 /*isPrimary*/);
@@ -1157,10 +1162,10 @@
// Fill in HEIC header
uint8_t *header = static_cast<uint8_t*>(dstBuffer) + mMaxHeicBufferSize - sizeof(CameraBlob);
- struct CameraBlob *blobHeader = (struct CameraBlob *)header;
+ CameraBlob *blobHeader = (CameraBlob *)header;
// Must be in sync with CAMERA3_HEIC_BLOB_ID in android_media_Utils.cpp
blobHeader->blobId = static_cast<CameraBlobId>(0x00FE);
- blobHeader->blobSize = fSize;
+ blobHeader->blobSizeBytes = fSize;
res = native_window_set_buffers_timestamp(mOutputSurface.get(), inputFrame.timestamp);
if (res != OK) {
@@ -1422,15 +1427,15 @@
size_t expectedSize = 0;
// First check for EXIF transport header at the end of the buffer
- const uint8_t *header = appSegmentBuffer + (maxSize - sizeof(struct CameraBlob));
- const struct CameraBlob *blob = (const struct CameraBlob*)(header);
+ const uint8_t *header = appSegmentBuffer + (maxSize - sizeof(CameraBlob));
+ const CameraBlob *blob = (const CameraBlob*)(header);
if (blob->blobId != CameraBlobId::JPEG_APP_SEGMENTS) {
- ALOGE("%s: Invalid EXIF blobId %hu", __FUNCTION__, blob->blobId);
+ ALOGE("%s: Invalid EXIF blobId %d", __FUNCTION__, blob->blobId);
return 0;
}
- expectedSize = blob->blobSize;
- if (expectedSize == 0 || expectedSize > maxSize - sizeof(struct CameraBlob)) {
+ expectedSize = blob->blobSizeBytes;
+ if (expectedSize == 0 || expectedSize > maxSize - sizeof(CameraBlob)) {
ALOGE("%s: Invalid blobSize %zu.", __FUNCTION__, expectedSize);
return 0;
}
@@ -1633,7 +1638,7 @@
maxAppsSegment = entry.data.u8[0] < 1 ? 1 :
entry.data.u8[0] > 16 ? 16 : entry.data.u8[0];
}
- return maxAppsSegment * (2 + 0xFFFF) + sizeof(struct CameraBlob);
+ return maxAppsSegment * (2 + 0xFFFF) + sizeof(CameraBlob);
}
void HeicCompositeStream::updateCodecQualityLocked(int32_t quality) {
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index 0ac047a..a7097fb 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -243,20 +243,23 @@
template <typename TClientBase>
binder::Status Camera2ClientBase<TClientBase>::disconnect() {
ATRACE_CALL();
+ ALOGD("Camera %s: start to disconnect", TClientBase::mCameraIdStr.string());
Mutex::Autolock icl(mBinderSerializationLock);
+ ALOGD("Camera %s: serializationLock acquired", TClientBase::mCameraIdStr.string());
binder::Status res = binder::Status::ok();
// Allow both client and the media server to disconnect at all times
int callingPid = CameraThreadState::getCallingPid();
if (callingPid != TClientBase::mClientPid &&
callingPid != TClientBase::mServicePid) return res;
- ALOGV("Camera %s: Shutting down", TClientBase::mCameraIdStr.string());
+ ALOGD("Camera %s: Shutting down", TClientBase::mCameraIdStr.string());
// Before detaching the device, cache the info from current open session.
// The disconnected check avoids duplication of info and also prevents
// deadlock while acquiring service lock in cacheDump.
if (!TClientBase::mDisconnected) {
+ ALOGD("Camera %s: start to cacheDump", TClientBase::mCameraIdStr.string());
Camera2ClientBase::getCameraService()->cacheDump();
}
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index 05edd6a..7e2f93c 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -35,6 +35,7 @@
#include "device3/StatusTracker.h"
#include "binder/Status.h"
#include "FrameProducer.h"
+#include "utils/IPCTransport.h"
#include "CameraOfflineSessionBase.h"
@@ -59,6 +60,9 @@
CAMERA_VENDOR_STREAM_CONFIGURATION_MODE_START = 0x8000
} camera_stream_configuration_mode_t;
+// Matches definition of camera3_jpeg_blob in camera3.h and HIDL definition
+// device@3.2:types.hal, needs to stay around till HIDL support is removed (for
+// HIDL -> AIDL cameraBlob translation)
typedef struct camera_jpeg_blob {
uint16_t jpeg_blob_id;
uint32_t jpeg_size;
@@ -88,6 +92,8 @@
public:
virtual ~CameraDeviceBase();
+ virtual IPCTransport getTransportType() const = 0;
+
/**
* The device vendor tag ID
*/
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index 4cc03f0..6edf1ac 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -40,7 +40,6 @@
#include <android-base/logging.h>
#include <cutils/properties.h>
#include <hwbinder/IPCThreadState.h>
-#include <utils/SessionConfigurationUtils.h>
#include <utils/Trace.h>
#include "api2/HeicCompositeStream.h"
@@ -338,14 +337,15 @@
status_t CameraProviderManager::isSessionConfigurationSupported(const std::string& id,
const SessionConfiguration &configuration, bool overrideForPerfClass,
- bool *status /*out*/) const {
+ metadataGetter getMetadata, bool *status /*out*/) const {
std::lock_guard<std::mutex> lock(mInterfaceMutex);
auto deviceInfo = findDeviceInfoLocked(id);
if (deviceInfo == nullptr) {
return NAME_NOT_FOUND;
}
- return deviceInfo->isSessionConfigurationSupported(configuration, overrideForPerfClass, status);
+ return deviceInfo->isSessionConfigurationSupported(configuration,
+ overrideForPerfClass, getMetadata, status);
}
status_t CameraProviderManager::getCameraIdIPCTransport(const std::string &id,
@@ -1243,6 +1243,34 @@
return OK;
}
+status_t CameraProviderManager::ProviderInfo::DeviceInfo3::fixupTorchStrengthTags() {
+ status_t res = OK;
+ auto& c = mCameraCharacteristics;
+ auto flashInfoStrengthDefaultLevelEntry = c.find(ANDROID_FLASH_INFO_STRENGTH_DEFAULT_LEVEL);
+ if (flashInfoStrengthDefaultLevelEntry.count == 0) {
+ int32_t flashInfoStrengthDefaultLevel = 1;
+ res = c.update(ANDROID_FLASH_INFO_STRENGTH_DEFAULT_LEVEL,
+ &flashInfoStrengthDefaultLevel, 1);
+ if (res != OK) {
+ ALOGE("%s: Failed to update ANDROID_FLASH_INFO_STRENGTH_DEFAULT_LEVEL: %s (%d)",
+ __FUNCTION__,strerror(-res), res);
+ return res;
+ }
+ }
+ auto flashInfoStrengthMaximumLevelEntry = c.find(ANDROID_FLASH_INFO_STRENGTH_MAXIMUM_LEVEL);
+ if (flashInfoStrengthMaximumLevelEntry.count == 0) {
+ int32_t flashInfoStrengthMaximumLevel = 1;
+ res = c.update(ANDROID_FLASH_INFO_STRENGTH_MAXIMUM_LEVEL,
+ &flashInfoStrengthMaximumLevel, 1);
+ if (res != OK) {
+ ALOGE("%s: Failed to update ANDROID_FLASH_INFO_STRENGTH_MAXIMUM_LEVEL: %s (%d)",
+ __FUNCTION__,strerror(-res), res);
+ return res;
+ }
+ }
+ return res;
+}
+
status_t CameraProviderManager::ProviderInfo::DeviceInfo3::fixupMonochromeTags() {
status_t res = OK;
auto& c = mCameraCharacteristics;
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index 3d108bd..3a366e5 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -33,6 +33,7 @@
#include <utils/Errors.h>
#include <android/hardware/ICameraService.h>
#include <utils/IPCTransport.h>
+#include <utils/SessionConfigurationUtils.h>
#include <aidl/android/hardware/camera/provider/ICameraProvider.h>
#include <android/hardware/camera/common/1.0/types.h>
#include <android/hardware/camera/provider/2.5/ICameraProvider.h>
@@ -278,7 +279,7 @@
*/
status_t isSessionConfigurationSupported(const std::string& id,
const SessionConfiguration &configuration,
- bool overrideForPerfClass,
+ bool overrideForPerfClass, camera3::metadataGetter getMetadata,
bool *status /*out*/) const;
/**
@@ -587,6 +588,7 @@
virtual status_t isSessionConfigurationSupported(
const SessionConfiguration &/*configuration*/,
bool /*overrideForPerfClass*/,
+ camera3::metadataGetter /*getMetadata*/,
bool * /*status*/) {
return INVALID_OPERATION;
}
@@ -639,6 +641,7 @@
CameraMetadata *characteristics) const override;
virtual status_t isSessionConfigurationSupported(
const SessionConfiguration &configuration, bool /*overrideForPerfClass*/,
+ camera3::metadataGetter /*getMetadata*/,
bool *status /*out*/) = 0;
virtual status_t filterSmallJpegSizes() override;
virtual void notifyDeviceStateChange(
@@ -658,10 +661,13 @@
// A copy of mCameraCharacteristics without performance class
// override
std::unique_ptr<CameraMetadata> mCameraCharNoPCOverride;
+ // Only contains characteristics for hidden physical cameras,
+ // not for public physical cameras.
std::unordered_map<std::string, CameraMetadata> mPhysicalCameraCharacteristics;
void queryPhysicalCameraIds();
SystemCameraKind getSystemCameraKind();
status_t fixupMonochromeTags();
+ status_t fixupTorchStrengthTags();
status_t addDynamicDepthTags(bool maxResolution = false);
status_t deriveHeicTags(bool maxResolution = false);
status_t addRotateCropTags();
diff --git a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
index 6f35e56..81b4779 100644
--- a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
+++ b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
@@ -538,6 +538,13 @@
if (flashAvailable.count == 1 &&
flashAvailable.data.u8[0] == ANDROID_FLASH_INFO_AVAILABLE_TRUE) {
mHasFlashUnit = true;
+ // Fix up flash strength tags for devices without these keys.
+ res = fixupTorchStrengthTags();
+ if (OK != res) {
+ ALOGE("%s: Unable to add default ANDROID_FLASH_INFO_STRENGTH_DEFAULT_LEVEL and"
+ "ANDROID_FLASH_INFO_STRENGTH_MAXIMUM_LEVEL tags: %s (%d)", __FUNCTION__,
+ strerror(-res), res);
+ }
} else {
mHasFlashUnit = false;
}
@@ -693,15 +700,11 @@
}
status_t AidlProviderInfo::AidlDeviceInfo3::isSessionConfigurationSupported(
- const SessionConfiguration &configuration, bool overrideForPerfClass, bool *status) {
+ const SessionConfiguration &configuration, bool overrideForPerfClass,
+ camera3::metadataGetter getMetadata, bool *status) {
camera::device::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);
diff --git a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.h b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.h
index aa71e85..97a8fed 100644
--- a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.h
+++ b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.h
@@ -129,7 +129,7 @@
virtual status_t isSessionConfigurationSupported(
const SessionConfiguration &/*configuration*/,
- bool overrideForPerfClass,
+ bool overrideForPerfClass, camera3::metadataGetter /*getMetadata*/,
bool *status/*status*/);
std::shared_ptr<aidl::android::hardware::camera::device::ICameraDevice>
diff --git a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
index 3c5ea75..b3cce1c 100644
--- a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
+++ b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
@@ -23,7 +23,7 @@
#include <camera_metadata_hidden.h>
#include "device3/ZoomRatioMapper.h"
-#include <utils/SessionConfigurationUtils.h>
+#include <utils/SessionConfigurationUtilsHidl.h>
#include <utils/Trace.h>
#include <android/hardware/camera/device/3.7/ICameraDevice.h>
@@ -662,6 +662,13 @@
if (flashAvailable.count == 1 &&
flashAvailable.data.u8[0] == ANDROID_FLASH_INFO_AVAILABLE_TRUE) {
mHasFlashUnit = true;
+ // Fix up flash strength tags for devices without these keys.
+ res = fixupTorchStrengthTags();
+ if (OK != res) {
+ ALOGE("%s: Unable to add default ANDROID_FLASH_INFO_STRENGTH_DEFAULT_LEVEL and"
+ "ANDROID_FLASH_INFO_STRENGTH_MAXIMUM_LEVEL tags: %s (%d)", __FUNCTION__,
+ strerror(-res), res);
+ }
} else {
mHasFlashUnit = false;
}
@@ -878,15 +885,11 @@
}
status_t HidlProviderInfo::HidlDeviceInfo3::isSessionConfigurationSupported(
- const SessionConfiguration &configuration, bool overrideForPerfClass, bool *status) {
+ const SessionConfiguration &configuration, bool overrideForPerfClass,
+ metadataGetter getMetadata, 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);
diff --git a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.h b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.h
index 4181fea..e0f1646 100644
--- a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.h
+++ b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.h
@@ -105,7 +105,7 @@
virtual status_t isSessionConfigurationSupported(
const SessionConfiguration &/*configuration*/,
- bool overrideForPerfClass,
+ bool overrideForPerfClass, camera3::metadataGetter getMetadata,
bool *status/*status*/);
sp<hardware::camera::device::V3_2::ICameraDevice> startDeviceInterface();
};
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 04e65d4..b133263 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -70,8 +70,6 @@
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 {
@@ -115,6 +113,10 @@
status_t Camera3Device::initializeCommonLocked() {
+ /** Start watchdog thread */
+ mCameraServiceWatchdog = new CameraServiceWatchdog();
+ mCameraServiceWatchdog->run("CameraServiceWatchdog");
+
/** Start up status tracker thread */
mStatusTracker = new StatusTracker(this);
status_t res = mStatusTracker->run(String8::format("C3Dev-%s-Status", mId.string()).string());
@@ -316,7 +318,7 @@
// Call close without internal mutex held, as the HAL close may need to
// wait on assorted callbacks,etc, to complete before it can return.
- interface->close();
+ mCameraServiceWatchdog->WATCH(interface->close());
flushInflightRequests();
@@ -339,6 +341,12 @@
}
}
ALOGI("%s: X", __FUNCTION__);
+
+ if (mCameraServiceWatchdog != NULL) {
+ mCameraServiceWatchdog->requestExit();
+ mCameraServiceWatchdog.clear();
+ }
+
return res;
}
@@ -528,10 +536,9 @@
}
lines.appendFormat(" Stream configuration:\n");
const char *mode =
- mOperatingMode == static_cast<int>(StreamConfigurationMode::NORMAL_MODE) ? "NORMAL" :
- mOperatingMode == static_cast<int>(
- StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE) ? "CONSTRAINED_HIGH_SPEED" :
- "CUSTOM";
+ mOperatingMode == CAMERA_STREAM_CONFIGURATION_NORMAL_MODE ? "NORMAL" :
+ mOperatingMode == CAMERA_STREAM_CONFIGURATION_CONSTRAINED_HIGH_SPEED_MODE ?
+ "CONSTRAINED_HIGH_SPEED" : "CUSTOM";
lines.appendFormat(" Operation mode: %s (%d) \n", mode, mOperatingMode);
if (mInputStream != NULL) {
@@ -1075,6 +1082,7 @@
ALOGE("%s: RAW opaque stream cannot be used with > 1 sensor pixel modes", __FUNCTION__);
return BAD_VALUE;
}
+ IPCTransport transport = getTransportType();
if (format == HAL_PIXEL_FORMAT_BLOB) {
ssize_t blobBufferSize;
if (dataSpace == HAL_DATASPACE_DEPTH) {
@@ -1094,7 +1102,7 @@
}
newStream = new Camera3OutputStream(mNextStreamId, consumers[0],
width, height, blobBufferSize, format, dataSpace, rotation,
- mTimestampOffset, physicalCameraId, sensorPixelModesUsed, streamSetId,
+ mTimestampOffset, physicalCameraId, sensorPixelModesUsed, transport, streamSetId,
isMultiResolution, dynamicRangeProfile, streamUseCase, mDeviceTimeBaseIsRealtime,
timestampBase, mirrorMode);
} else if (format == HAL_PIXEL_FORMAT_RAW_OPAQUE) {
@@ -1109,25 +1117,25 @@
}
newStream = new Camera3OutputStream(mNextStreamId, consumers[0],
width, height, rawOpaqueBufferSize, format, dataSpace, rotation,
- mTimestampOffset, physicalCameraId, sensorPixelModesUsed, streamSetId,
+ mTimestampOffset, physicalCameraId, sensorPixelModesUsed, transport, streamSetId,
isMultiResolution, dynamicRangeProfile, streamUseCase, mDeviceTimeBaseIsRealtime,
timestampBase, mirrorMode);
} else if (isShared) {
newStream = new Camera3SharedOutputStream(mNextStreamId, consumers,
width, height, format, consumerUsage, dataSpace, rotation,
- mTimestampOffset, physicalCameraId, sensorPixelModesUsed, streamSetId,
+ mTimestampOffset, physicalCameraId, sensorPixelModesUsed, transport, streamSetId,
mUseHalBufManager, dynamicRangeProfile, streamUseCase, mDeviceTimeBaseIsRealtime,
timestampBase, mirrorMode);
} else if (consumers.size() == 0 && hasDeferredConsumer) {
newStream = new Camera3OutputStream(mNextStreamId,
width, height, format, consumerUsage, dataSpace, rotation,
- mTimestampOffset, physicalCameraId, sensorPixelModesUsed, streamSetId,
+ mTimestampOffset, physicalCameraId, sensorPixelModesUsed, transport, streamSetId,
isMultiResolution, dynamicRangeProfile, streamUseCase, mDeviceTimeBaseIsRealtime,
timestampBase, mirrorMode);
} else {
newStream = new Camera3OutputStream(mNextStreamId, consumers[0],
width, height, format, dataSpace, rotation,
- mTimestampOffset, physicalCameraId, sensorPixelModesUsed, streamSetId,
+ mTimestampOffset, physicalCameraId, sensorPixelModesUsed, transport, streamSetId,
isMultiResolution, dynamicRangeProfile, streamUseCase, mDeviceTimeBaseIsRealtime,
timestampBase, mirrorMode);
}
@@ -1549,13 +1557,22 @@
}
bool stateSeen = false;
+ nsecs_t startTime = systemTime();
do {
if (active == (mStatus == STATUS_ACTIVE)) {
// Desired state is current
break;
}
- res = mStatusChanged.waitRelative(mLock, timeout);
+ nsecs_t timeElapsed = systemTime() - startTime;
+ nsecs_t timeToWait = timeout - timeElapsed;
+ if (timeToWait <= 0) {
+ // Thread woke up spuriously but has timed out since.
+ // Force out of loop with TIMED_OUT result.
+ res = TIMED_OUT;
+ break;
+ }
+ res = mStatusChanged.waitRelative(mLock, timeToWait);
if (res != OK) break;
// This is impossible, but if not, could result in subtle deadlocks and invalid state
@@ -1719,7 +1736,12 @@
mSessionStatsBuilder.stopCounter();
}
- return mRequestThread->flush();
+ // Calculate expected duration for flush with additional buffer time in ms for watchdog
+ uint64_t maxExpectedDuration = (getExpectedInFlightDuration() + kBaseGetBufferWait) / 1e6;
+ status_t res = mCameraServiceWatchdog->WATCH_CUSTOM_TIMER(mRequestThread->flush(),
+ maxExpectedDuration / kCycleLengthMs, kCycleLengthMs);
+
+ return res;
}
status_t Camera3Device::prepare(int streamId) {
@@ -2261,8 +2283,7 @@
}
bool isConstrainedHighSpeed =
- static_cast<int>(StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE) ==
- operatingMode;
+ CAMERA_STREAM_CONFIGURATION_CONSTRAINED_HIGH_SPEED_MODE == operatingMode;
if (mOperatingMode != operatingMode) {
mNeedConfig = true;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 749b342..f927b4d 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -31,7 +31,9 @@
#include <camera/CaptureResult.h>
-#include "android/hardware/camera/metadata/3.8/types.h"
+#include "CameraServiceWatchdog.h"
+#include <aidl/android/hardware/camera/device/CameraBlob.h>
+
#include "common/CameraDeviceBase.h"
#include "device3/BufferUtils.h"
#include "device3/StatusTracker.h"
@@ -50,7 +52,6 @@
#include <camera_metadata_hidden.h>
using android::camera3::camera_capture_request_t;
-using android::camera3::camera_jpeg_blob_t;
using android::camera3::camera_request_template;
using android::camera3::camera_stream_buffer_t;
using android::camera3::camera_stream_configuration_t;
@@ -88,7 +89,9 @@
static void cleanupNativeHandles(
std::vector<native_handle_t*> *handles, bool closeFd = false);
- IPCTransport getTransportType() { return mInterface->getTransportType(); }
+ virtual IPCTransport getTransportType() const override {
+ return mInterface->getTransportType();
+ }
/**
* CameraDeviceBase interface
@@ -98,6 +101,9 @@
metadata_vendor_id_t getVendorTagId() const override { return mVendorTagId; }
+ // Watchdog thread
+ sp<CameraServiceWatchdog> mCameraServiceWatchdog;
+
// Transitions to idle state on success.
virtual status_t initialize(sp<CameraProviderManager> /*manager*/,
const String8& /*monitorTags*/) = 0;
@@ -309,7 +315,8 @@
struct RequestTrigger;
// minimal jpeg buffer size: 256KB + blob header
- static const ssize_t kMinJpegBufferSize = 256 * 1024 + sizeof(camera_jpeg_blob_t);
+ static const ssize_t kMinJpegBufferSize =
+ 256 * 1024 + sizeof(aidl::android::hardware::camera::device::CameraBlob);
// Constant to use for stream ID when one doesn't exist
static const int NO_STREAM = -1;
@@ -353,7 +360,7 @@
HalInterface(const HalInterface &other);
HalInterface();
- virtual IPCTransport getTransportType() = 0;
+ virtual IPCTransport getTransportType() const = 0;
// Returns true if constructed with a valid device or session, and not yet cleared
virtual bool valid() = 0;
diff --git a/services/camera/libcameraservice/device3/Camera3DeviceInjectionMethods.cpp b/services/camera/libcameraservice/device3/Camera3DeviceInjectionMethods.cpp
index 6818acf..031c255 100644
--- a/services/camera/libcameraservice/device3/Camera3DeviceInjectionMethods.cpp
+++ b/services/camera/libcameraservice/device3/Camera3DeviceInjectionMethods.cpp
@@ -26,8 +26,6 @@
namespace android {
-using hardware::camera::device::V3_2::ICameraDeviceSession;
-
Camera3Device::Camera3DeviceInjectionMethods::Camera3DeviceInjectionMethods(
wp<Camera3Device> parent)
: mParent(parent) {
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index 37f9227..b21322c 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -21,12 +21,16 @@
#include <ctime>
#include <fstream>
+#include <aidl/android/hardware/camera/device/CameraBlob.h>
+#include <aidl/android/hardware/camera/device/CameraBlobId.h>
+
#include <android-base/unique_fd.h>
#include <cutils/properties.h>
#include <ui/GraphicBuffer.h>
#include <utils/Log.h>
#include <utils/Trace.h>
+#include <common/CameraDeviceBase.h>
#include "api1/client2/JpegProcessor.h"
#include "Camera3OutputStream.h"
#include "utils/TraceHFR.h"
@@ -40,12 +44,15 @@
namespace camera3 {
+using aidl::android::hardware::camera::device::CameraBlob;
+using aidl::android::hardware::camera::device::CameraBlobId;
+
Camera3OutputStream::Camera3OutputStream(int id,
sp<Surface> consumer,
uint32_t width, uint32_t height, int format,
android_dataspace dataSpace, camera_stream_rotation_t rotation,
nsecs_t timestampOffset, const String8& physicalCameraId,
- const std::unordered_set<int32_t> &sensorPixelModesUsed,
+ const std::unordered_set<int32_t> &sensorPixelModesUsed, IPCTransport transport,
int setId, bool isMultiResolution, int64_t dynamicRangeProfile,
int64_t streamUseCase, bool deviceTimeBaseIsRealtime, int timestampBase,
int mirrorMode) :
@@ -62,7 +69,8 @@
mConsumerUsage(0),
mDropBuffers(false),
mMirrorMode(mirrorMode),
- mDequeueBufferLatency(kDequeueLatencyBinSize) {
+ mDequeueBufferLatency(kDequeueLatencyBinSize),
+ mIPCTransport(transport) {
if (mConsumer == NULL) {
ALOGE("%s: Consumer is NULL!", __FUNCTION__);
@@ -78,7 +86,7 @@
uint32_t width, uint32_t height, size_t maxSize, int format,
android_dataspace dataSpace, camera_stream_rotation_t rotation,
nsecs_t timestampOffset, const String8& physicalCameraId,
- const std::unordered_set<int32_t> &sensorPixelModesUsed,
+ const std::unordered_set<int32_t> &sensorPixelModesUsed, IPCTransport transport,
int setId, bool isMultiResolution, int64_t dynamicRangeProfile,
int64_t streamUseCase, bool deviceTimeBaseIsRealtime, int timestampBase,
int mirrorMode) :
@@ -94,7 +102,8 @@
mConsumerUsage(0),
mDropBuffers(false),
mMirrorMode(mirrorMode),
- mDequeueBufferLatency(kDequeueLatencyBinSize) {
+ mDequeueBufferLatency(kDequeueLatencyBinSize),
+ mIPCTransport(transport) {
if (format != HAL_PIXEL_FORMAT_BLOB && format != HAL_PIXEL_FORMAT_RAW_OPAQUE) {
ALOGE("%s: Bad format for size-only stream: %d", __FUNCTION__,
@@ -116,7 +125,7 @@
uint64_t consumerUsage, android_dataspace dataSpace,
camera_stream_rotation_t rotation, nsecs_t timestampOffset,
const String8& physicalCameraId,
- const std::unordered_set<int32_t> &sensorPixelModesUsed,
+ const std::unordered_set<int32_t> &sensorPixelModesUsed, IPCTransport transport,
int setId, bool isMultiResolution, int64_t dynamicRangeProfile,
int64_t streamUseCase, bool deviceTimeBaseIsRealtime, int timestampBase,
int mirrorMode) :
@@ -133,7 +142,8 @@
mConsumerUsage(consumerUsage),
mDropBuffers(false),
mMirrorMode(mirrorMode),
- mDequeueBufferLatency(kDequeueLatencyBinSize) {
+ mDequeueBufferLatency(kDequeueLatencyBinSize),
+ mIPCTransport(transport) {
// Deferred consumer only support preview surface format now.
if (format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
ALOGE("%s: Deferred consumer only supports IMPLEMENTATION_DEFINED format now!",
@@ -161,6 +171,7 @@
camera_stream_rotation_t rotation,
const String8& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
+ IPCTransport transport,
uint64_t consumerUsage, nsecs_t timestampOffset,
int setId, bool isMultiResolution,
int64_t dynamicRangeProfile, int64_t streamUseCase,
@@ -179,7 +190,8 @@
mConsumerUsage(consumerUsage),
mDropBuffers(false),
mMirrorMode(mirrorMode),
- mDequeueBufferLatency(kDequeueLatencyBinSize) {
+ mDequeueBufferLatency(kDequeueLatencyBinSize),
+ mIPCTransport(transport) {
bool needsReleaseNotify = setId > CAMERA3_STREAM_SET_ID_INVALID;
mBufferProducerListener = new BufferProducerListener(this, needsReleaseNotify);
@@ -303,6 +315,73 @@
return OK;
}
+status_t Camera3OutputStream::fixUpHidlJpegBlobHeader(ANativeWindowBuffer* anwBuffer, int fence) {
+ // Lock the JPEG buffer for CPU read
+ sp<GraphicBuffer> graphicBuffer = GraphicBuffer::from(anwBuffer);
+ void* mapped = nullptr;
+ base::unique_fd fenceFd(dup(fence));
+ // Use USAGE_SW_WRITE_RARELY since we're going to re-write the CameraBlob
+ // header.
+ GraphicBufferLocker gbLocker(graphicBuffer);
+ status_t res =
+ gbLocker.lockAsync(
+ GraphicBuffer::USAGE_SW_READ_OFTEN | GraphicBuffer::USAGE_SW_WRITE_RARELY,
+ &mapped, fenceFd.get());
+ if (res != OK) {
+ ALOGE("%s: Failed to lock the buffer: %s (%d)", __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+
+ uint8_t *hidlHeaderStart =
+ static_cast<uint8_t*>(mapped) + graphicBuffer->getWidth() - sizeof(camera_jpeg_blob_t);
+ // Check that the jpeg buffer is big enough to contain HIDL camera blob
+ if (hidlHeaderStart < static_cast<uint8_t *>(mapped)) {
+ ALOGE("%s, jpeg buffer not large enough to fit HIDL camera blob %" PRIu32, __FUNCTION__,
+ graphicBuffer->getWidth());
+ return BAD_VALUE;
+ }
+ camera_jpeg_blob_t *hidlBlobHeader = reinterpret_cast<camera_jpeg_blob_t *>(hidlHeaderStart);
+
+ // Check that the blob is indeed the jpeg blob id.
+ if (hidlBlobHeader->jpeg_blob_id != CAMERA_JPEG_BLOB_ID) {
+ ALOGE("%s, jpeg blob id %d is not correct", __FUNCTION__, hidlBlobHeader->jpeg_blob_id);
+ return BAD_VALUE;
+ }
+
+ // Retrieve id and blob size
+ CameraBlobId blobId = static_cast<CameraBlobId>(hidlBlobHeader->jpeg_blob_id);
+ uint32_t blobSizeBytes = hidlBlobHeader->jpeg_size;
+
+ if (blobSizeBytes > (graphicBuffer->getWidth() - sizeof(camera_jpeg_blob_t))) {
+ ALOGE("%s, blobSize in HIDL jpeg blob : %d is corrupt, buffer size %" PRIu32, __FUNCTION__,
+ blobSizeBytes, graphicBuffer->getWidth());
+ }
+
+ uint8_t *aidlHeaderStart =
+ static_cast<uint8_t*>(mapped) + graphicBuffer->getWidth() - sizeof(CameraBlob);
+
+ // Check that the jpeg buffer is big enough to contain AIDL camera blob
+ if (aidlHeaderStart < static_cast<uint8_t *>(mapped)) {
+ ALOGE("%s, jpeg buffer not large enough to fit AIDL camera blob %" PRIu32, __FUNCTION__,
+ graphicBuffer->getWidth());
+ return BAD_VALUE;
+ }
+
+ if (static_cast<uint8_t*>(mapped) + blobSizeBytes > aidlHeaderStart) {
+ ALOGE("%s, jpeg blob with size %d , buffer size %" PRIu32 " not large enough to fit"
+ " AIDL camera blob without corrupting jpeg", __FUNCTION__, blobSizeBytes,
+ graphicBuffer->getWidth());
+ return BAD_VALUE;
+ }
+
+ // Fill in JPEG header
+ CameraBlob *aidlBlobHeader = reinterpret_cast<CameraBlob *>(aidlHeaderStart);
+ aidlBlobHeader->blobId = blobId;
+ aidlBlobHeader->blobSizeBytes = blobSizeBytes;
+ graphicBuffer->unlock();
+ return OK;
+}
+
status_t Camera3OutputStream::returnBufferCheckedLocked(
const camera_stream_buffer &buffer,
nsecs_t timestamp,
@@ -368,32 +447,47 @@
}
mTraceFirstBuffer = false;
}
-
- // If this is a JPEG output, and image dump mask is set, save image to
- // disk.
- if (getFormat() == HAL_PIXEL_FORMAT_BLOB && getDataSpace() == HAL_DATASPACE_V0_JFIF &&
- mImageDumpMask) {
- dumpImageToDisk(timestamp, anwBuffer, anwReleaseFence);
+ // Fix CameraBlob id type discrepancy between HIDL and AIDL, details : http://b/229688810
+ if (getFormat() == HAL_PIXEL_FORMAT_BLOB && getDataSpace() == HAL_DATASPACE_V0_JFIF) {
+ if (mIPCTransport == IPCTransport::HIDL) {
+ fixUpHidlJpegBlobHeader(anwBuffer, anwReleaseFence);
+ }
+ // If this is a JPEG output, and image dump mask is set, save image to
+ // disk.
+ if (mImageDumpMask) {
+ dumpImageToDisk(timestamp, anwBuffer, anwReleaseFence);
+ }
}
- nsecs_t captureTime = (mSyncToDisplay ? readoutTimestamp : timestamp) - mTimestampOffset;
- nsecs_t presentTime = mSyncToDisplay ?
- syncTimestampToDisplayLocked(captureTime) : captureTime;
+ if (mPreviewFrameSpacer != nullptr) {
+ res = mPreviewFrameSpacer->queuePreviewBuffer(timestamp - mTimestampOffset, transform,
+ anwBuffer, anwReleaseFence);
+ if (res != OK) {
+ ALOGE("%s: Stream %d: Error queuing buffer to preview buffer spacer: %s (%d)",
+ __FUNCTION__, mId, strerror(-res), res);
+ return res;
+ }
+ } else {
+ nsecs_t captureTime = (mSyncToDisplay ? readoutTimestamp : timestamp)
+ - mTimestampOffset;
+ nsecs_t presentTime = mSyncToDisplay ?
+ syncTimestampToDisplayLocked(captureTime) : captureTime;
- setTransform(transform, true/*mayChangeMirror*/);
- res = native_window_set_buffers_timestamp(mConsumer.get(), presentTime);
- if (res != OK) {
- ALOGE("%s: Stream %d: Error setting timestamp: %s (%d)",
- __FUNCTION__, mId, strerror(-res), res);
- return res;
- }
+ setTransform(transform, true/*mayChangeMirror*/);
+ res = native_window_set_buffers_timestamp(mConsumer.get(), presentTime);
+ if (res != OK) {
+ ALOGE("%s: Stream %d: Error setting timestamp: %s (%d)",
+ __FUNCTION__, mId, strerror(-res), res);
+ return res;
+ }
- queueHDRMetadata(anwBuffer->handle, currentConsumer, dynamic_range_profile);
+ 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:"
- " %s (%d)", __FUNCTION__, mId, strerror(-res), res);
+ res = queueBufferToConsumer(currentConsumer, anwBuffer, anwReleaseFence, surface_ids);
+ if (shouldLogError(res, state)) {
+ ALOGE("%s: Stream %d: Error queueing buffer to native window:"
+ " %s (%d)", __FUNCTION__, mId, strerror(-res), res);
+ }
}
}
mLock.lock();
@@ -468,7 +562,7 @@
return res;
}
- if ((res = configureConsumerQueueLocked(true /*allowDisplaySync*/)) != OK) {
+ if ((res = configureConsumerQueueLocked(true /*allowPreviewRespace*/)) != OK) {
return res;
}
@@ -492,7 +586,7 @@
return OK;
}
-status_t Camera3OutputStream::configureConsumerQueueLocked(bool allowDisplaySync) {
+status_t Camera3OutputStream::configureConsumerQueueLocked(bool allowPreviewRespace) {
status_t res;
mTraceFirstBuffer = true;
@@ -582,20 +676,25 @@
int timestampBase = getTimestampBase();
bool isDefaultTimeBase = (timestampBase ==
OutputConfiguration::TIMESTAMP_BASE_DEFAULT);
- if (allowDisplaySync) {
- // We cannot distinguish between a SurfaceView and an ImageReader of
- // preview buffer format. Frames are synchronized to display in both
- // cases.
+ if (allowPreviewRespace) {
bool forceChoreographer = (timestampBase ==
OutputConfiguration::TIMESTAMP_BASE_CHOREOGRAPHER_SYNCED);
- bool defaultToChoreographer = (isDefaultTimeBase && isConsumedByHWComposer() &&
+ bool defaultToChoreographer = (isDefaultTimeBase &&
+ isConsumedByHWComposer() &&
!property_get_bool("camera.disable_preview_scheduler", false));
if (forceChoreographer || defaultToChoreographer) {
mSyncToDisplay = true;
mTotalBufferCount += kDisplaySyncExtraBuffer;
+ } else if (isConsumedByHWTexture() && !isVideoStream()) {
+ mPreviewFrameSpacer = new PreviewFrameSpacer(*this, mConsumer);
+ mTotalBufferCount ++;
+ res = mPreviewFrameSpacer->run(String8::format("PreviewSpacer-%d", mId).string());
+ if (res != OK) {
+ ALOGE("%s: Unable to start preview spacer", __FUNCTION__);
+ return res;
+ }
}
}
-
mHandoutTotalBufferCount = 0;
mFrameCount = 0;
mLastTimestamp = 0;
@@ -1316,6 +1415,11 @@
return expectedPresentT - vsyncEventData.frameInterval/3;
}
+bool Camera3OutputStream::shouldLogError(status_t res) {
+ Mutex::Autolock l(mLock);
+ return shouldLogError(res, mState);
+}
+
}; // namespace camera3
}; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index 6ea7ef7..45e995d 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -23,11 +23,13 @@
#include <gui/Surface.h>
#include <gui/DisplayEventReceiver.h>
+#include "utils/IPCTransport.h"
#include "utils/LatencyHistogram.h"
#include "Camera3Stream.h"
#include "Camera3IOStreamBase.h"
#include "Camera3OutputStreamInterface.h"
#include "Camera3BufferManager.h"
+#include "PreviewFrameSpacer.h"
namespace android {
@@ -88,7 +90,7 @@
uint32_t width, uint32_t height, int format,
android_dataspace dataSpace, camera_stream_rotation_t rotation,
nsecs_t timestampOffset, const String8& physicalCameraId,
- const std::unordered_set<int32_t> &sensorPixelModesUsed,
+ const std::unordered_set<int32_t> &sensorPixelModesUsed, IPCTransport transport,
int setId = CAMERA3_STREAM_SET_ID_INVALID, bool isMultiResolution = false,
int64_t dynamicProfile = ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD,
int64_t streamUseCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
@@ -105,7 +107,7 @@
uint32_t width, uint32_t height, size_t maxSize, int format,
android_dataspace dataSpace, camera_stream_rotation_t rotation,
nsecs_t timestampOffset, const String8& physicalCameraId,
- const std::unordered_set<int32_t> &sensorPixelModesUsed,
+ const std::unordered_set<int32_t> &sensorPixelModesUsed, IPCTransport transport,
int setId = CAMERA3_STREAM_SET_ID_INVALID, bool isMultiResolution = false,
int64_t dynamicProfile = ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD,
int64_t streamUseCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
@@ -121,7 +123,7 @@
uint64_t consumerUsage, android_dataspace dataSpace,
camera_stream_rotation_t rotation, nsecs_t timestampOffset,
const String8& physicalCameraId,
- const std::unordered_set<int32_t> &sensorPixelModesUsed,
+ const std::unordered_set<int32_t> &sensorPixelModesUsed, IPCTransport transport,
int setId = CAMERA3_STREAM_SET_ID_INVALID, bool isMultiResolution = false,
int64_t dynamicProfile = ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD,
int64_t streamUseCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
@@ -250,13 +252,14 @@
static void applyZSLUsageQuirk(int format, uint64_t *consumerUsage /*inout*/);
void setImageDumpMask(int mask) { mImageDumpMask = mask; }
+ bool shouldLogError(status_t res);
protected:
Camera3OutputStream(int id, camera_stream_type_t type,
uint32_t width, uint32_t height, int format,
android_dataspace dataSpace, camera_stream_rotation_t rotation,
const String8& physicalCameraId,
- const std::unordered_set<int32_t> &sensorPixelModesUsed,
+ const std::unordered_set<int32_t> &sensorPixelModesUsed, IPCTransport transport,
uint64_t consumerUsage = 0, nsecs_t timestampOffset = 0,
int setId = CAMERA3_STREAM_SET_ID_INVALID, bool isMultiResolution = false,
int64_t dynamicProfile = ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD,
@@ -279,10 +282,11 @@
sp<Fence> *releaseFenceOut);
virtual status_t disconnectLocked();
+ status_t fixUpHidlJpegBlobHeader(ANativeWindowBuffer* anwBuffer, int fence);
status_t getEndpointUsageForSurface(uint64_t *usage,
const sp<Surface>& surface) const;
- status_t configureConsumerQueueLocked(bool allowDisplaySync);
+ status_t configureConsumerQueueLocked(bool allowPreviewRespace);
// Consumer as the output of camera HAL
sp<Surface> mConsumer;
@@ -396,15 +400,15 @@
void returnPrefetchedBuffersLocked();
- // Synchronize camera timestamp to display, and the return value
- // can be used as presentation timestamp
- nsecs_t syncTimestampToDisplayLocked(nsecs_t t);
static const int32_t kDequeueLatencyBinSize = 5; // in ms
CameraLatencyHistogram mDequeueBufferLatency;
+ IPCTransport mIPCTransport = IPCTransport::INVALID;
int mImageDumpMask = 0;
+ // Re-space frames by overriding timestamp to align with display Vsync.
+ // Default is on for SurfaceView bound streams.
nsecs_t mMinExpectedDuration = 0;
bool mSyncToDisplay = false;
DisplayEventReceiver mDisplayEventReceiver;
@@ -414,6 +418,12 @@
static constexpr size_t kDisplaySyncExtraBuffer = 2;
static constexpr nsecs_t kSpacingResetIntervalNs = 1000000000LL; // 1 second
static constexpr nsecs_t kTimelineThresholdNs = 1000000LL; // 1 millisecond
+ nsecs_t syncTimestampToDisplayLocked(nsecs_t t);
+
+ // Re-space frames by delaying queueBuffer so that frame delivery has
+ // the same cadence as capture. Default is on for SurfaceTexture bound
+ // streams.
+ sp<PreviewFrameSpacer> mPreviewFrameSpacer;
}; // class Camera3OutputStream
} // namespace camera3
diff --git a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
index d24b527..9215f23 100644
--- a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
@@ -32,15 +32,15 @@
uint64_t consumerUsage, android_dataspace dataSpace,
camera_stream_rotation_t rotation,
nsecs_t timestampOffset, const String8& physicalCameraId,
- const std::unordered_set<int32_t> &sensorPixelModesUsed,
+ const std::unordered_set<int32_t> &sensorPixelModesUsed, IPCTransport transport,
int setId, bool useHalBufManager, int64_t dynamicProfile,
int64_t streamUseCase, bool deviceTimeBaseIsRealtime, int timestampBase,
int mirrorMode) :
Camera3OutputStream(id, CAMERA_STREAM_OUTPUT, width, height,
format, dataSpace, rotation, physicalCameraId, sensorPixelModesUsed,
- consumerUsage, timestampOffset, setId, /*isMultiResolution*/false,
- dynamicProfile, streamUseCase, deviceTimeBaseIsRealtime, timestampBase,
- mirrorMode),
+ transport, consumerUsage, timestampOffset, setId,
+ /*isMultiResolution*/false, dynamicProfile, streamUseCase,
+ deviceTimeBaseIsRealtime, timestampBase, mirrorMode),
mUseHalBufManager(useHalBufManager) {
size_t consumerCount = std::min(surfaces.size(), kMaxOutputs);
if (surfaces.size() > consumerCount) {
@@ -251,7 +251,7 @@
return res;
}
- res = configureConsumerQueueLocked(false/*allowDisplaySync*/);
+ res = configureConsumerQueueLocked(false/*allowPreviewRespace*/);
if (res != OK) {
ALOGE("Failed to configureConsumerQueueLocked: %s(%d)", strerror(-res), res);
return res;
diff --git a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
index 8f7f00b..aac3c2a 100644
--- a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
@@ -38,7 +38,7 @@
uint64_t consumerUsage, android_dataspace dataSpace,
camera_stream_rotation_t rotation, nsecs_t timestampOffset,
const String8& physicalCameraId,
- const std::unordered_set<int32_t> &sensorPixelModesUsed,
+ const std::unordered_set<int32_t> &sensorPixelModesUsed, IPCTransport transport,
int setId = CAMERA3_STREAM_SET_ID_INVALID,
bool useHalBufManager = false,
int64_t dynamicProfile = ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD,
diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
index 5c333a4..6812e89 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
@@ -130,6 +130,43 @@
streamUseCase(_streamUseCase), timestampBase(_timestampBase), mirrorMode(_mirrorMode) {}
};
+// Utility class to lock and unlock a GraphicBuffer
+class GraphicBufferLocker {
+public:
+ GraphicBufferLocker(sp<GraphicBuffer> buffer) : _buffer(buffer) {}
+
+ status_t lockAsync(uint32_t usage, void** dstBuffer, int fenceFd) {
+ if (_buffer == nullptr) return BAD_VALUE;
+
+ status_t res = OK;
+ if (!_locked) {
+ status_t res = _buffer->lockAsync(usage, dstBuffer, fenceFd);
+ if (res == OK) {
+ _locked = true;
+ }
+ }
+ return res;
+ }
+
+ status_t lockAsync(void** dstBuffer, int fenceFd) {
+ return lockAsync(GRALLOC_USAGE_SW_WRITE_OFTEN, dstBuffer, fenceFd);
+ }
+
+ ~GraphicBufferLocker() {
+ if (_locked && _buffer != nullptr) {
+ auto res = _buffer->unlock();
+ if (res != OK) {
+ ALOGE("%s: Error trying to unlock buffer: %s (%d)", __FUNCTION__,
+ strerror(-res), res);
+ }
+ }
+ }
+
+private:
+ sp<GraphicBuffer> _buffer;
+ bool _locked = false;
+};
+
/**
* An interface for managing a single stream of input and/or output data from
* the camera device.
diff --git a/services/camera/libcameraservice/device3/PreviewFrameSpacer.cpp b/services/camera/libcameraservice/device3/PreviewFrameSpacer.cpp
new file mode 100644
index 0000000..9112b93
--- /dev/null
+++ b/services/camera/libcameraservice/device3/PreviewFrameSpacer.cpp
@@ -0,0 +1,122 @@
+/*
+ * 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 "Camera3-PreviewFrameSpacer"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+
+#include "PreviewFrameSpacer.h"
+#include "Camera3OutputStream.h"
+
+namespace android {
+
+namespace camera3 {
+
+PreviewFrameSpacer::PreviewFrameSpacer(Camera3OutputStream& parent, sp<Surface> consumer) :
+ mParent(parent),
+ mConsumer(consumer) {
+}
+
+PreviewFrameSpacer::~PreviewFrameSpacer() {
+ Thread::requestExitAndWait();
+}
+
+status_t PreviewFrameSpacer::queuePreviewBuffer(nsecs_t timestamp, int32_t transform,
+ ANativeWindowBuffer* anwBuffer, int releaseFence) {
+ Mutex::Autolock l(mLock);
+ mPendingBuffers.emplace(timestamp, transform, anwBuffer, releaseFence);
+ ALOGV("%s: mPendingBuffers size %zu, timestamp %" PRId64, __FUNCTION__,
+ mPendingBuffers.size(), timestamp);
+
+ mBufferCond.signal();
+ return OK;
+}
+
+bool PreviewFrameSpacer::threadLoop() {
+ Mutex::Autolock l(mLock);
+ if (mPendingBuffers.size() == 0) {
+ mBufferCond.waitRelative(mLock, kWaitDuration);
+ return true;
+ }
+
+ nsecs_t currentTime = systemTime();
+ auto buffer = mPendingBuffers.front();
+ nsecs_t captureInterval = buffer.timestamp - mLastCameraCaptureTime;
+ // If the capture interval exceeds threshold, directly queue
+ // cached buffer.
+ if (captureInterval >= kFrameIntervalThreshold) {
+ mPendingBuffers.pop();
+ queueBufferToClientLocked(buffer, currentTime);
+ return true;
+ }
+
+ // Cache the frame to match capture time interval, for up to 33ms
+ nsecs_t expectedQueueTime = mLastCameraPresentTime + captureInterval;
+ nsecs_t frameWaitTime = std::min(kMaxFrameWaitTime, expectedQueueTime - currentTime);
+ if (frameWaitTime > 0 && mPendingBuffers.size() < 2) {
+ mBufferCond.waitRelative(mLock, frameWaitTime);
+ if (exitPending()) {
+ return true;
+ }
+ currentTime = systemTime();
+ }
+ ALOGV("%s: captureInterval %" PRId64 ", queueInterval %" PRId64 ", waited for %" PRId64
+ ", timestamp %" PRId64, __FUNCTION__, captureInterval,
+ currentTime - mLastCameraPresentTime, frameWaitTime, buffer.timestamp);
+ mPendingBuffers.pop();
+ queueBufferToClientLocked(buffer, currentTime);
+ return true;
+}
+
+void PreviewFrameSpacer::requestExit() {
+ // Call parent to set up shutdown
+ Thread::requestExit();
+ // Exit from other possible wait
+ mBufferCond.signal();
+}
+
+void PreviewFrameSpacer::queueBufferToClientLocked(
+ const BufferHolder& bufferHolder, nsecs_t currentTime) {
+ mParent.setTransform(bufferHolder.transform, true/*mayChangeMirror*/);
+
+ status_t res = native_window_set_buffers_timestamp(mConsumer.get(), bufferHolder.timestamp);
+ if (res != OK) {
+ ALOGE("%s: Preview Stream: Error setting timestamp: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ }
+
+ Camera3Stream::queueHDRMetadata(bufferHolder.anwBuffer.get()->handle, mConsumer,
+ mParent.getDynamicRangeProfile());
+
+ res = mConsumer->queueBuffer(mConsumer.get(), bufferHolder.anwBuffer.get(),
+ bufferHolder.releaseFence);
+ if (res != OK) {
+ close(bufferHolder.releaseFence);
+ if (mParent.shouldLogError(res)) {
+ ALOGE("%s: Failed to queue buffer to client: %s(%d)", __FUNCTION__,
+ strerror(-res), res);
+ }
+ }
+
+ mLastCameraPresentTime = currentTime;
+ mLastCameraCaptureTime = bufferHolder.timestamp;
+}
+
+}; // namespace camera3
+
+}; // namespace android
diff --git a/services/camera/libcameraservice/device3/PreviewFrameSpacer.h b/services/camera/libcameraservice/device3/PreviewFrameSpacer.h
new file mode 100644
index 0000000..5062553
--- /dev/null
+++ b/services/camera/libcameraservice/device3/PreviewFrameSpacer.h
@@ -0,0 +1,93 @@
+/*
+ * 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_CAMERA3_PREVIEWFRAMESPACER_H
+#define ANDROID_SERVERS_CAMERA_CAMERA3_PREVIEWFRAMESPACER_H
+
+#include <queue>
+
+#include <gui/Surface.h>
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
+#include <utils/Thread.h>
+#include <utils/Timers.h>
+
+namespace android {
+
+namespace camera3 {
+
+class Camera3OutputStream;
+
+/***
+ * Preview stream spacer for better frame spacing
+ *
+ * The ideal viewfinder user experience is that frames are presented to the
+ * user in the same cadence as outputed by the camera sensor. However, the
+ * processing latency between frames could vary, due to factors such
+ * as CPU load, differences in request settings, etc. This frame processing
+ * latency results in variation in presentation of frames to the user.
+ *
+ * The PreviewFrameSpacer improves the viewfinder user experience by:
+ * - Cache the frame buffers if the intervals between queueBuffer is shorter
+ * than the camera capture intervals.
+ * - Queue frame buffers in the same cadence as the camera capture time.
+ * - Maintain at most 1 queue-able buffer. If the 2nd preview buffer becomes
+ * available, queue the oldest cached buffer to the buffer queue.
+ */
+class PreviewFrameSpacer : public Thread {
+ public:
+ explicit PreviewFrameSpacer(Camera3OutputStream& parent, sp<Surface> consumer);
+ virtual ~PreviewFrameSpacer();
+
+ // Queue preview buffer locally
+ status_t queuePreviewBuffer(nsecs_t timestamp, int32_t transform,
+ ANativeWindowBuffer* anwBuffer, int releaseFence);
+
+ bool threadLoop() override;
+ void requestExit() override;
+
+ private:
+ // structure holding cached preview buffer info
+ struct BufferHolder {
+ nsecs_t timestamp;
+ int32_t transform;
+ sp<ANativeWindowBuffer> anwBuffer;
+ int releaseFence;
+
+ BufferHolder(nsecs_t t, int32_t tr, ANativeWindowBuffer* anwb, int rf) :
+ timestamp(t), transform(tr), anwBuffer(anwb), releaseFence(rf) {}
+ };
+
+ void queueBufferToClientLocked(const BufferHolder& bufferHolder, nsecs_t currentTime);
+
+
+ Camera3OutputStream& mParent;
+ sp<ANativeWindow> mConsumer;
+ mutable Mutex mLock;
+ Condition mBufferCond;
+
+ std::queue<BufferHolder> mPendingBuffers;
+ nsecs_t mLastCameraCaptureTime = 0;
+ nsecs_t mLastCameraPresentTime = 0;
+ static constexpr nsecs_t kWaitDuration = 5000000LL; // 50ms
+ static constexpr nsecs_t kFrameIntervalThreshold = 80000000LL; // 80ms
+ static constexpr nsecs_t kMaxFrameWaitTime = 33333333LL; // 33ms
+};
+
+}; //namespace camera3
+}; //namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.h b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.h
index e7a7eec..d20a7eb 100644
--- a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.h
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.h
@@ -84,7 +84,7 @@
std::shared_ptr<AidlRequestMetadataQueue> queue,
bool useHalBufManager, bool supportOfflineProcessing);
- virtual IPCTransport getTransportType() {return IPCTransport::AIDL; }
+ virtual IPCTransport getTransportType() const override {return IPCTransport::AIDL; }
// Returns true if constructed with a valid device or session, and not yet cleared
diff --git a/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp
index cf6d462..6d76687 100644
--- a/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp
+++ b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp
@@ -52,7 +52,7 @@
#include "device3/hidl/HidlCamera3OutputUtils.h"
#include "device3/hidl/HidlCamera3OfflineSession.h"
-#include "utils/SessionConfigurationUtils.h"
+#include "utils/SessionConfigurationUtilsHidl.h"
#include "utils/TraceHFR.h"
#include "../../common/hidl/HidlProviderInfo.h"
diff --git a/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.h b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.h
index 77d539a..56c999a 100644
--- a/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.h
+++ b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.h
@@ -102,7 +102,7 @@
std::shared_ptr<RequestMetadataQueue> queue,
bool useHalBufManager, bool supportOfflineProcessing);
- virtual IPCTransport getTransportType() override { return IPCTransport::HIDL; }
+ virtual IPCTransport getTransportType() const override { return IPCTransport::HIDL; }
// Returns true if constructed with a valid device or session, and not yet cleared
virtual bool valid() override;
diff --git a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp
index a00b221..f7cede8 100644
--- a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp
+++ b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp
@@ -260,4 +260,16 @@
sessionStats->onClose(latencyMs);
}
+bool CameraServiceProxyWrapper::isCameraDisabled() {
+ sp<ICameraServiceProxy> proxyBinder = getCameraServiceProxy();
+ if (proxyBinder == nullptr) return true;
+ bool ret = false;
+ auto status = proxyBinder->isCameraDisabled(&ret);
+ if (!status.isOk()) {
+ ALOGE("%s: Failed during camera disabled query: %s", __FUNCTION__,
+ status.exceptionMessage().c_str());
+ }
+ return ret;
+}
+
}; // namespace android
diff --git a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.h b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.h
index 6604aa1..61fc915 100644
--- a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.h
+++ b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.h
@@ -95,6 +95,9 @@
// Return the current top activity rotate and crop override.
static int getRotateAndCropOverride(String16 packageName, int lensFacing, int userId);
+
+ // Detect if the camera is disabled by device policy.
+ static bool isCameraDisabled();
};
} // android
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
index 4090dae..9f8f457 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
@@ -31,9 +31,6 @@
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;
-using android::hardware::camera::metadata::V3_8::CameraMetadataEnumAndroidScalerAvailableStreamUseCases;
namespace android {
namespace camera3 {
@@ -322,6 +319,10 @@
streamUseCase == ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT) {
return true;
}
+ // Allow vendor stream use case unconditionally.
+ if (streamUseCase >= ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VENDOR_START) {
+ return true;
+ }
for (size_t i = 0; i < availableStreamUseCases.count; i++) {
if (availableStreamUseCases.data.i64[i] == streamUseCase) {
@@ -558,72 +559,6 @@
stream->useCase = static_cast<StreamUseCases>(streamInfo.streamUseCase);
}
-status_t
-convertAidlToHidl38StreamCombination(
- const aidl::android::hardware::camera::device::StreamConfiguration &aidl,
- hardware::camera::device::V3_8::StreamConfiguration &hidl) {
- hidl.operationMode =
- static_cast<hardware::camera::device::V3_2::StreamConfigurationMode>(aidl.operationMode);
- if (aidl.streamConfigCounter < 0) {
- return BAD_VALUE;
- }
- hidl.streamConfigCounter = static_cast<uint32_t>(aidl.streamConfigCounter);
- hidl.multiResolutionInputImage = aidl.multiResolutionInputImage;
- hidl.sessionParams = aidl.sessionParams.metadata;
- hidl.streams.resize(aidl.streams.size());
- size_t i = 0;
- for (const auto &stream : aidl.streams) {
- //hidlv3_8
- hidl.streams[i].dynamicRangeProfile =
- static_cast<
- CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap>
- (stream.dynamicRangeProfile);
- hidl.streams[i].useCase =
- static_cast<
- CameraMetadataEnumAndroidScalerAvailableStreamUseCases>
- (stream.useCase);
-
- // hidl v3_7
- hidl.streams[i].v3_7.groupId = stream.groupId;
- hidl.streams[i].v3_7.sensorPixelModesUsed.resize(stream.sensorPixelModesUsed.size());
- size_t j = 0;
- for (const auto &mode : stream.sensorPixelModesUsed) {
- hidl.streams[i].v3_7.sensorPixelModesUsed[j] =
- static_cast<CameraMetadataEnumAndroidSensorPixelMode>(mode);
- j++;
- }
-
- //hidl v3_4
- hidl.streams[i].v3_7.v3_4.physicalCameraId = stream.physicalCameraId;
-
- if (stream.bufferSize < 0) {
- return BAD_VALUE;
- }
- hidl.streams[i].v3_7.v3_4.bufferSize = static_cast<uint32_t>(stream.bufferSize);
-
- // hild v3_2
- hidl.streams[i].v3_7.v3_4.v3_2.id = stream.id;
- hidl.streams[i].v3_7.v3_4.v3_2.format =
- static_cast<hardware::graphics::common::V1_0::PixelFormat>(stream.format);
-
- if (stream.width < 0 || stream.height < 0) {
- return BAD_VALUE;
- }
- hidl.streams[i].v3_7.v3_4.v3_2.width = static_cast<uint32_t>(stream.width);
- hidl.streams[i].v3_7.v3_4.v3_2.height = static_cast<uint32_t>(stream.height);
- hidl.streams[i].v3_7.v3_4.v3_2.usage =
- static_cast<hardware::camera::device::V3_2::BufferUsageFlags>(stream.usage);
- hidl.streams[i].v3_7.v3_4.v3_2.streamType =
- static_cast<hardware::camera::device::V3_2::StreamType>(stream.streamType);
- hidl.streams[i].v3_7.v3_4.v3_2.dataSpace =
- static_cast<hardware::camera::device::V3_2::DataspaceFlags>(stream.dataSpace);
- hidl.streams[i].v3_7.v3_4.v3_2.rotation =
- static_cast<hardware::camera::device::V3_2::StreamRotation>(stream.rotation);
- i++;
- }
- return OK;
-}
-
binder::Status
convertToHALStreamCombination(
const SessionConfiguration& sessionConfiguration,
@@ -813,40 +748,6 @@
return binder::Status::ok();
}
-void mapStreamInfo(const OutputStreamInfo &streamInfo,
- camera3::camera_stream_rotation_t rotation, String8 physicalId,
- int32_t groupId, hardware::camera::device::V3_8::Stream *stream /*out*/) {
- if (stream == nullptr) {
- return;
- }
-
- 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_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->v3_7.sensorPixelModesUsed[idx++] =
- static_cast<CameraMetadataEnumAndroidSensorPixelMode>(mode);
- }
- stream->dynamicRangeProfile =
- static_cast<CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap> (
- streamInfo.dynamicRangeProfile);
- stream->useCase = static_cast<CameraMetadataEnumAndroidScalerAvailableStreamUseCases>(
- streamInfo.streamUseCase);
-}
-
binder::Status checkPhysicalCameraId(
const std::vector<std::string> &physicalCameraIds, const String8 &physicalCameraId,
const String8 &logicalCameraId) {
@@ -919,32 +820,6 @@
return binder::Status::ok();
}
-binder::Status
-convertToHALStreamCombination(
- const SessionConfiguration& sessionConfiguration,
- const String8 &logicalCameraId, const CameraMetadata &deviceInfo,
- metadataGetter getMetadata, const std::vector<std::string> &physicalCameraIds,
- hardware::camera::device::V3_8::StreamConfiguration &streamConfiguration,
- bool overrideForPerfClass, bool *earlyExit) {
- aidl::android::hardware::camera::device::StreamConfiguration aidlStreamConfiguration;
- auto ret = convertToHALStreamCombination(sessionConfiguration, logicalCameraId, deviceInfo,
- getMetadata, physicalCameraIds, aidlStreamConfiguration, overrideForPerfClass,
- earlyExit);
- if (!ret.isOk()) {
- return ret;
- }
- if (earlyExit != nullptr && *earlyExit) {
- return binder::Status::ok();
- }
-
- if (convertAidlToHidl38StreamCombination(aidlStreamConfiguration, streamConfiguration) != OK) {
- return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
- "Invalid AIDL->HIDL3.8 conversion");
- }
-
- return binder::Status::ok();
-}
-
static bool inStreamConfigurationMap(int format, int width, int height,
const std::unordered_map<int, std::vector<camera3::StreamConfiguration>> &sm) {
auto scs = sm.find(format);
@@ -1029,53 +904,6 @@
return OK;
}
-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<int64_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;
- }
- if (static_cast<int64_t>(streamConfigV38.streams[i].useCase) !=
- ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT) {
- // ICameraDevice older than 3.8 doesn't support stream use case
- return false;
- }
- streamConfigV37.streams[i] = streamConfigV38.streams[i].v3_7;
- }
- streamConfigV37.operationMode = streamConfigV38.operationMode;
- streamConfigV37.sessionParams = streamConfigV38.sessionParams;
-
- return true;
-}
-
-bool convertHALStreamCombinationFromV37ToV34(
- hardware::camera::device::V3_4::StreamConfiguration &streamConfigV34,
- const hardware::camera::device::V3_7::StreamConfiguration &streamConfigV37) {
- if (streamConfigV37.multiResolutionInputImage) {
- // ICameraDevice older than 3.7 doesn't support multi-resolution input image.
- return false;
- }
-
- streamConfigV34.streams.resize(streamConfigV37.streams.size());
- for (size_t i = 0; i < streamConfigV37.streams.size(); i++) {
- if (streamConfigV37.streams[i].groupId != -1) {
- // ICameraDevice older than 3.7 doesn't support multi-resolution output
- // image
- return false;
- }
- streamConfigV34.streams[i] = streamConfigV37.streams[i].v3_4;
- }
- streamConfigV34.operationMode = streamConfigV37.operationMode;
- streamConfigV34.sessionParams = streamConfigV37.sessionParams;
-
- return true;
-}
-
bool targetPerfClassPrimaryCamera(
const std::set<std::string>& perfClassPrimaryCameraIds, const std::string& cameraId,
int targetSdkVersion) {
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.h b/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
index 8abcc95..97ca6b7 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
@@ -28,6 +28,7 @@
#include <android/hardware/camera/device/3.8/ICameraDeviceSession.h>
#include <device3/Camera3StreamInterface.h>
+#include <utils/IPCTransport.h>
#include <set>
#include <stdint.h>
@@ -48,7 +49,7 @@
namespace android {
namespace camera3 {
-typedef std::function<CameraMetadata (const String8 &, int targetSdkVersion)> metadataGetter;
+typedef std::function<CameraMetadata (const String8 &, bool overrideForPerfClass)> metadataGetter;
class StreamConfiguration {
public:
@@ -101,10 +102,6 @@
const std::vector<int32_t> &sensorPixelModesUsed, int64_t dynamicRangeProfile,
int64_t streamUseCase, int timestampBase, int mirrorMode);
-void mapStreamInfo(const camera3::OutputStreamInfo &streamInfo,
- camera3::camera_stream_rotation_t rotation, String8 physicalId, int32_t groupId,
- hardware::camera::device::V3_8::Stream *stream /*out*/);
-
//check if format is 10-bit output compatible
bool is10bitCompatibleFormat(int32_t format);
@@ -132,24 +129,6 @@
binder::Status checkOperatingMode(int operatingMode,
const CameraMetadata &staticInfo, const String8 &cameraId);
-// 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);
-
-// 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);
-
binder::Status
convertToHALStreamCombination(
const SessionConfiguration& sessionConfiguration,
@@ -158,13 +137,6 @@
aidl::android::hardware::camera::device::StreamConfiguration &streamConfiguration,
bool overrideForPerfClass, bool *earlyExit);
-// Utility function to convert a V3_7::StreamConfiguration to
-// V3_4::StreamConfiguration. Return false if the original V3_7 configuration cannot
-// be used by older version HAL.
-bool convertHALStreamCombinationFromV37ToV34(
- hardware::camera::device::V3_4::StreamConfiguration &streamConfigV34,
- const hardware::camera::device::V3_7::StreamConfiguration &streamConfigV37);
-
StreamConfigurationPair getStreamConfigurationPair(const CameraMetadata &metadata);
status_t checkAndOverrideSensorPixelModesUsed(
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtilsHidl.cpp b/services/camera/libcameraservice/utils/SessionConfigurationUtilsHidl.cpp
new file mode 100644
index 0000000..07b55e1
--- /dev/null
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtilsHidl.cpp
@@ -0,0 +1,213 @@
+/*
+ * 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 <cutils/properties.h>
+
+#include "SessionConfigurationUtils.h"
+#include "SessionConfigurationUtilsHidl.h"
+
+#include "../CameraService.h"
+#include "device3/aidl/AidlCamera3Device.h"
+#include "device3/hidl/HidlCamera3Device.h"
+#include "device3/Camera3OutputStream.h"
+
+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;
+using android::hardware::camera::metadata::V3_8::CameraMetadataEnumAndroidScalerAvailableStreamUseCases;
+
+namespace android {
+namespace camera3 {
+
+namespace SessionConfigurationUtils {
+
+status_t
+convertAidlToHidl38StreamCombination(
+ const aidl::android::hardware::camera::device::StreamConfiguration &aidl,
+ hardware::camera::device::V3_8::StreamConfiguration &hidl) {
+ hidl.operationMode =
+ static_cast<hardware::camera::device::V3_2::StreamConfigurationMode>(aidl.operationMode);
+ if (aidl.streamConfigCounter < 0) {
+ return BAD_VALUE;
+ }
+ hidl.streamConfigCounter = static_cast<uint32_t>(aidl.streamConfigCounter);
+ hidl.multiResolutionInputImage = aidl.multiResolutionInputImage;
+ hidl.sessionParams = aidl.sessionParams.metadata;
+ hidl.streams.resize(aidl.streams.size());
+ size_t i = 0;
+ for (const auto &stream : aidl.streams) {
+ //hidlv3_8
+ hidl.streams[i].dynamicRangeProfile =
+ static_cast<
+ CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap>
+ (stream.dynamicRangeProfile);
+ hidl.streams[i].useCase =
+ static_cast<
+ CameraMetadataEnumAndroidScalerAvailableStreamUseCases>
+ (stream.useCase);
+
+ // hidl v3_7
+ hidl.streams[i].v3_7.groupId = stream.groupId;
+ hidl.streams[i].v3_7.sensorPixelModesUsed.resize(stream.sensorPixelModesUsed.size());
+ size_t j = 0;
+ for (const auto &mode : stream.sensorPixelModesUsed) {
+ hidl.streams[i].v3_7.sensorPixelModesUsed[j] =
+ static_cast<CameraMetadataEnumAndroidSensorPixelMode>(mode);
+ j++;
+ }
+
+ //hidl v3_4
+ hidl.streams[i].v3_7.v3_4.physicalCameraId = stream.physicalCameraId;
+
+ if (stream.bufferSize < 0) {
+ return BAD_VALUE;
+ }
+ hidl.streams[i].v3_7.v3_4.bufferSize = static_cast<uint32_t>(stream.bufferSize);
+
+ // hild v3_2
+ hidl.streams[i].v3_7.v3_4.v3_2.id = stream.id;
+ hidl.streams[i].v3_7.v3_4.v3_2.format =
+ static_cast<hardware::graphics::common::V1_0::PixelFormat>(stream.format);
+
+ if (stream.width < 0 || stream.height < 0) {
+ return BAD_VALUE;
+ }
+ hidl.streams[i].v3_7.v3_4.v3_2.width = static_cast<uint32_t>(stream.width);
+ hidl.streams[i].v3_7.v3_4.v3_2.height = static_cast<uint32_t>(stream.height);
+ hidl.streams[i].v3_7.v3_4.v3_2.usage =
+ static_cast<hardware::camera::device::V3_2::BufferUsageFlags>(stream.usage);
+ hidl.streams[i].v3_7.v3_4.v3_2.streamType =
+ static_cast<hardware::camera::device::V3_2::StreamType>(stream.streamType);
+ hidl.streams[i].v3_7.v3_4.v3_2.dataSpace =
+ static_cast<hardware::camera::device::V3_2::DataspaceFlags>(stream.dataSpace);
+ hidl.streams[i].v3_7.v3_4.v3_2.rotation =
+ static_cast<hardware::camera::device::V3_2::StreamRotation>(stream.rotation);
+ i++;
+ }
+ return OK;
+}
+
+void mapStreamInfo(const OutputStreamInfo &streamInfo,
+ camera3::camera_stream_rotation_t rotation, String8 physicalId,
+ int32_t groupId, hardware::camera::device::V3_8::Stream *stream /*out*/) {
+ if (stream == nullptr) {
+ return;
+ }
+
+ 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_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->v3_7.sensorPixelModesUsed[idx++] =
+ static_cast<CameraMetadataEnumAndroidSensorPixelMode>(mode);
+ }
+ stream->dynamicRangeProfile =
+ static_cast<CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap> (
+ streamInfo.dynamicRangeProfile);
+ stream->useCase = static_cast<CameraMetadataEnumAndroidScalerAvailableStreamUseCases>(
+ streamInfo.streamUseCase);
+}
+
+binder::Status
+convertToHALStreamCombination(
+ const SessionConfiguration& sessionConfiguration,
+ const String8 &logicalCameraId, const CameraMetadata &deviceInfo,
+ metadataGetter getMetadata, const std::vector<std::string> &physicalCameraIds,
+ hardware::camera::device::V3_8::StreamConfiguration &streamConfiguration,
+ bool overrideForPerfClass, bool *earlyExit) {
+ aidl::android::hardware::camera::device::StreamConfiguration aidlStreamConfiguration;
+ auto ret = convertToHALStreamCombination(sessionConfiguration, logicalCameraId, deviceInfo,
+ getMetadata, physicalCameraIds, aidlStreamConfiguration, overrideForPerfClass,
+ earlyExit);
+ if (!ret.isOk()) {
+ return ret;
+ }
+ if (earlyExit != nullptr && *earlyExit) {
+ return binder::Status::ok();
+ }
+
+ if (convertAidlToHidl38StreamCombination(aidlStreamConfiguration, streamConfiguration) != OK) {
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
+ "Invalid AIDL->HIDL3.8 conversion");
+ }
+
+ return binder::Status::ok();
+}
+
+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<int64_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;
+ }
+ if (static_cast<int64_t>(streamConfigV38.streams[i].useCase) !=
+ ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT) {
+ // ICameraDevice older than 3.8 doesn't support stream use case
+ return false;
+ }
+ streamConfigV37.streams[i] = streamConfigV38.streams[i].v3_7;
+ }
+ streamConfigV37.operationMode = streamConfigV38.operationMode;
+ streamConfigV37.sessionParams = streamConfigV38.sessionParams;
+
+ return true;
+}
+
+bool convertHALStreamCombinationFromV37ToV34(
+ hardware::camera::device::V3_4::StreamConfiguration &streamConfigV34,
+ const hardware::camera::device::V3_7::StreamConfiguration &streamConfigV37) {
+ if (streamConfigV37.multiResolutionInputImage) {
+ // ICameraDevice older than 3.7 doesn't support multi-resolution input image.
+ return false;
+ }
+
+ streamConfigV34.streams.resize(streamConfigV37.streams.size());
+ for (size_t i = 0; i < streamConfigV37.streams.size(); i++) {
+ if (streamConfigV37.streams[i].groupId != -1) {
+ // ICameraDevice older than 3.7 doesn't support multi-resolution output
+ // image
+ return false;
+ }
+ streamConfigV34.streams[i] = streamConfigV37.streams[i].v3_4;
+ }
+ streamConfigV34.operationMode = streamConfigV37.operationMode;
+ streamConfigV34.sessionParams = streamConfigV37.sessionParams;
+
+ return true;
+}
+
+} // namespace SessionConfigurationUtils
+} // namespace camera3
+} // namespace android
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtilsHidl.h b/services/camera/libcameraservice/utils/SessionConfigurationUtilsHidl.h
new file mode 100644
index 0000000..66956c5
--- /dev/null
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtilsHidl.h
@@ -0,0 +1,65 @@
+/*
+ * 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_SESSION_CONFIGURATION_UTILS_HIDL_H
+#define ANDROID_SERVERS_CAMERA_SESSION_CONFIGURATION_UTILS_HIDL_H
+
+#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 <utils/SessionConfigurationUtils.h>
+
+// Convenience methods for constructing binder::Status objects for error returns
+
+namespace android {
+namespace camera3 {
+
+namespace SessionConfigurationUtils {
+
+void mapStreamInfo(const camera3::OutputStreamInfo &streamInfo,
+ camera3::camera_stream_rotation_t rotation, String8 physicalId, int32_t groupId,
+ hardware::camera::device::V3_8::Stream *stream /*out*/);
+
+// 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);
+
+// 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);
+
+// 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);
+} // SessionConfigurationUtils
+} // camera3
+} // android
+
+#endif
diff --git a/services/mediametrics/AudioTypes.cpp b/services/mediametrics/AudioTypes.cpp
index 594809c..6e24a58 100644
--- a/services/mediametrics/AudioTypes.cpp
+++ b/services/mediametrics/AudioTypes.cpp
@@ -128,6 +128,9 @@
{"AUDIO_DEVICE_OUT_BLE_HEADSET", 1LL << 31},
{"AUDIO_DEVICE_OUT_BLE_SPEAKER", 1LL << 32},
{"AUDIO_DEVICE_OUT_HDMI_EARC", 1LL << 33},
+ // S values above
+ {"AUDIO_DEVICE_OUT_BLE_BROADCAST", 1LL << 34},
+ // T values above
};
return map;
}
@@ -145,6 +148,8 @@
{"MMAP_PLAYBACK", 5}, // Thread class for MMAP playback stream
{"MMAP_CAPTURE", 6}, // Thread class for MMAP capture stream
// R values above.
+ {"SPATIALIZER", 7}, // Thread class for SpatializerThread
+ // S values above.
};
return map;
}
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index e0584df..b4610bc 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -732,6 +732,7 @@
return true;
}
+ int failedClientPid = -1;
{
Mutex::Autolock lock(mLock);
bool found = false;
@@ -746,11 +747,14 @@
}
}
if (found) {
+ failedClientPid = mMap.keyAt(i);
break;
}
}
- if (!found) {
- ALOGV("didn't find failed client");
+ if (found) {
+ ALOGW("Failed to reclaim resources from client with pid %d", failedClientPid);
+ } else {
+ ALOGW("Failed to reclaim resources from unlocateable client");
}
}
diff --git a/services/mediaresourcemanager/fuzzer/mediaresourcemanager_fuzzer.cpp b/services/mediaresourcemanager/fuzzer/mediaresourcemanager_fuzzer.cpp
index 8f25ee6..e4aaea0 100644
--- a/services/mediaresourcemanager/fuzzer/mediaresourcemanager_fuzzer.cpp
+++ b/services/mediaresourcemanager/fuzzer/mediaresourcemanager_fuzzer.cpp
@@ -227,33 +227,31 @@
mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinThreadPairs, kMaxThreadPairs);
// Make even number of threads
size_t numThreads = numThreadPairs * 2;
- resourceThreadArgs threadArgs;
- vector<MediaResourceParcel> mediaResource;
+ resourceThreadArgs threadArgs[numThreadPairs];
+ vector<MediaResourceParcel> mediaResource[numThreadPairs];
pthread_t pt[numThreads];
- int i;
- for (i = 0; i < numThreads - 1; i += 2) {
- threadArgs.pid = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
- threadArgs.uid = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
+ for (int k = 0; k < numThreadPairs; ++k) {
+ threadArgs[k].pid = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
+ threadArgs[k].uid = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
int32_t mediaResourceType = mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(
kMinResourceType, kMaxResourceType);
int32_t mediaResourceSubType = mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(
kMinResourceType, kMaxResourceType);
uint64_t mediaResourceValue = mFuzzedDataProvider->ConsumeIntegral<uint64_t>();
- threadArgs.service = mService;
+ threadArgs[k].service = mService;
shared_ptr<IResourceManagerClient> testClient =
- ::ndk::SharedRefBase::make<TestClient>(threadArgs.pid, mService);
- threadArgs.testClient = testClient;
- threadArgs.testClientId = getId(testClient);
- mediaResource.push_back(MediaResource(static_cast<MedResType>(mediaResourceType),
- static_cast<MedResSubType>(mediaResourceSubType),
- mediaResourceValue));
- threadArgs.mediaResource = mediaResource;
- pthread_create(&pt[i], nullptr, addResource, &threadArgs);
- pthread_create(&pt[i + 1], nullptr, removeResource, &threadArgs);
- mediaResource.clear();
+ ::ndk::SharedRefBase::make<TestClient>(threadArgs[k].pid, mService);
+ threadArgs[k].testClient = testClient;
+ threadArgs[k].testClientId = getId(testClient);
+ mediaResource[k].push_back(MediaResource(static_cast<MedResType>(mediaResourceType),
+ static_cast<MedResSubType>(mediaResourceSubType),
+ mediaResourceValue));
+ threadArgs[k].mediaResource = mediaResource[k];
+ pthread_create(&pt[2 * k], nullptr, addResource, &threadArgs[k]);
+ pthread_create(&pt[2 * k + 1], nullptr, removeResource, &threadArgs[k]);
}
- for (i = 0; i < numThreads; ++i) {
+ for (int i = 0; i < numThreads; ++i) {
pthread_join(pt[i], nullptr);
}
@@ -266,14 +264,14 @@
int32_t mediaResourceSubType =
mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(kMinResourceType, kMaxResourceType);
uint64_t mediaResourceValue = mFuzzedDataProvider->ConsumeIntegral<uint64_t>();
- mediaResource.push_back(MediaResource(static_cast<MedResType>(mediaResourceType),
- static_cast<MedResSubType>(mediaResourceSubType),
- mediaResourceValue));
+ vector<MediaResourceParcel> mediaRes;
+ mediaRes.push_back(MediaResource(static_cast<MedResType>(mediaResourceType),
+ static_cast<MedResSubType>(mediaResourceSubType),
+ mediaResourceValue));
bool result;
- mService->reclaimResource(pidZero, mediaResource, &result);
- mService->removeResource(pidZero, getId(testClient), mediaResource);
+ mService->reclaimResource(pidZero, mediaRes, &result);
+ mService->removeResource(pidZero, getId(testClient), mediaRes);
mService->removeClient(pidZero, getId(testClient));
- mediaResource.clear();
}
void ResourceManagerServiceFuzzer::setServiceLog() {
diff --git a/services/tuner/hidl/TunerHidlFilter.cpp b/services/tuner/hidl/TunerHidlFilter.cpp
index 6d8ae03..fe74a5c 100644
--- a/services/tuner/hidl/TunerHidlFilter.cpp
+++ b/services/tuner/hidl/TunerHidlFilter.cpp
@@ -390,7 +390,9 @@
static_cast<int32_t>(Result::INVALID_STATE));
}
- HidlResult res = mFilter->releaseAvHandle(hidl_handle(makeFromAidl(in_handle)), in_avDataId);
+ hidl_handle handle;
+ handle.setTo(makeFromAidl(in_handle), true);
+ HidlResult res = mFilter->releaseAvHandle(handle, in_avDataId);
if (res != HidlResult::SUCCESS) {
return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
}