Merge "Update logging logic in AudioStream." into sc-dev
diff --git a/apex/mediatranscoding.rc b/apex/mediatranscoding.rc
index fa4acf8..ae9f8ba 100644
--- a/apex/mediatranscoding.rc
+++ b/apex/mediatranscoding.rc
@@ -6,5 +6,7 @@
user media
group media
ioprio rt 4
- task_profiles ProcessCapacityHigh HighPerformance
+ # Restrict to little cores only with system-background cpuset.
+ writepid /dev/cpuset/system-background/tasks
+ interface aidl media.transcoding
disabled
diff --git a/camera/Android.bp b/camera/Android.bp
index 2c01496..6878c20 100644
--- a/camera/Android.bp
+++ b/camera/Android.bp
@@ -119,6 +119,8 @@
"aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl",
"aidl/android/hardware/camera2/ICameraDeviceUser.aidl",
"aidl/android/hardware/camera2/ICameraOfflineSession.aidl",
+ "aidl/android/hardware/camera2/ICameraInjectionCallback.aidl",
+ "aidl/android/hardware/camera2/ICameraInjectionSession.aidl",
],
path: "aidl",
}
diff --git a/camera/aidl/android/hardware/ICameraService.aidl b/camera/aidl/android/hardware/ICameraService.aidl
index 459ad15..873d738 100644
--- a/camera/aidl/android/hardware/ICameraService.aidl
+++ b/camera/aidl/android/hardware/ICameraService.aidl
@@ -20,6 +20,8 @@
import android.hardware.ICameraClient;
import android.hardware.camera2.ICameraDeviceUser;
import android.hardware.camera2.ICameraDeviceCallbacks;
+import android.hardware.camera2.ICameraInjectionCallback;
+import android.hardware.camera2.ICameraInjectionSession;
import android.hardware.camera2.params.VendorTagDescriptor;
import android.hardware.camera2.params.VendorTagDescriptorCache;
import android.hardware.camera2.utils.ConcurrentCameraIdCombination;
@@ -161,6 +163,9 @@
boolean supportsCameraApi(String cameraId, int apiVersion);
// Determines if a cameraId is a hidden physical camera of a logical multi-camera.
boolean isHiddenPhysicalCamera(String cameraId);
+ // Inject the external camera to replace the internal camera session.
+ ICameraInjectionSession injectCamera(String packageName, String internalCamId,
+ String externalCamId, in ICameraInjectionCallback CameraInjectionCallback);
void setTorchMode(String cameraId, boolean enabled, IBinder clientBinder);
diff --git a/camera/aidl/android/hardware/camera2/ICameraInjectionCallback.aidl b/camera/aidl/android/hardware/camera2/ICameraInjectionCallback.aidl
new file mode 100644
index 0000000..9791352
--- /dev/null
+++ b/camera/aidl/android/hardware/camera2/ICameraInjectionCallback.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2;
+
+import android.hardware.camera2.ICameraInjectionSession;
+
+/**
+ * Binder interface used to call back the error state injected by the external camera,
+ * and camera service can be switched back to internal camera when binder signals process death.
+ *
+ * @hide
+ */
+interface ICameraInjectionCallback
+{
+ // Error codes for onInjectionError
+ // To indicate all invalid error codes
+ const int ERROR_INJECTION_INVALID_ERROR = -1;
+ // To indicate the camera injection session has encountered a fatal error, such as injection
+ // init failure, configure failure or injecting failure etc.
+ const int ERROR_INJECTION_SESSION = 0;
+ // To indicate the camera service has encountered a fatal error.
+ const int ERROR_INJECTION_SERVICE = 1;
+ // To indicate the injection camera does not support certain camera functions, such as
+ // unsupport stream format, no capture/record function or no multi-camera function etc.
+ // When this error occurs, the default processing is still in the inject state, and the app is
+ // notified to display an error message and a black screen.
+ const int ERROR_INJECTION_UNSUPPORTED = 2;
+
+ oneway void onInjectionError(int errorCode);
+}
diff --git a/camera/aidl/android/hardware/camera2/ICameraInjectionSession.aidl b/camera/aidl/android/hardware/camera2/ICameraInjectionSession.aidl
new file mode 100644
index 0000000..c31c30b
--- /dev/null
+++ b/camera/aidl/android/hardware/camera2/ICameraInjectionSession.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2;
+
+/** @hide */
+interface ICameraInjectionSession
+{
+ oneway void stopInjection();
+}
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 20ffd48..d1b4ede 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -3578,7 +3578,7 @@
* android.scaler.availableInputOutputFormatsMap.</p>
* <p>The following table describes the minimum required output stream
* configurations based on the hardware level
- * (ACAMERA_INFO_SUPPORTED_HARDWARE_LEVEL):</p>
+ * (ACAMERA_INFO_SUPPORTED_HARDWARE_LEVEL), prior to Android 12:</p>
* <p>Format | Size | Hardware Level | Notes
* :-------------:|:--------------------------------------------:|:--------------:|:--------------:
* JPEG | ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE | Any |
@@ -3589,6 +3589,21 @@
* YUV_420_888 | all output sizes available for JPEG | FULL |
* YUV_420_888 | all output sizes available for JPEG, up to the maximum video size | LIMITED |
* IMPLEMENTATION_DEFINED | same as YUV_420_888 | Any |</p>
+ * <p>Starting from Android 12, the camera device may not support JPEG sizes smaller than the
+ * minimum of 1080p and the camera sensor active array size. The requirements for
+ * IMPLEMENTATION_DEFINED and YUV_420_888 stay the same. This new minimum required output
+ * stream configurations are illustrated by the table below:</p>
+ * <p>Format | Size | Hardware Level | Notes
+ * :-------------:|:--------------------------------------------:|:--------------:|:--------------:
+ * JPEG | ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE | Any |
+ * JPEG | 1920x1080 (1080p) | Any | if 1080p <= activeArraySize
+ * YUV_420_888 | ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE | FULL |
+ * YUV_420_888 | 1920x1080 (1080p) | FULL | if 1080p <= activeArraySize
+ * YUV_420_888 | 1280x720 (720) | FULL | if 720p <= activeArraySize
+ * YUV_420_888 | 640x480 (480p) | FULL | if 480p <= activeArraySize
+ * YUV_420_888 | 320x240 (240p) | FULL | if 240p <= activeArraySize
+ * YUV_420_888 | all output sizes available for FULL hardware level, up to the maximum video size | LIMITED |
+ * IMPLEMENTATION_DEFINED | same as YUV_420_888 | Any |</p>
* <p>Refer to ACAMERA_REQUEST_AVAILABLE_CAPABILITIES for additional
* mandatory stream configurations on a per-capability basis.</p>
* <p>Exception on 176x144 (QCIF) resolution: camera devices usually have a fixed capability for
diff --git a/drm/mediadrm/plugins/clearkey/hidl/AesCtrDecryptor.cpp b/drm/mediadrm/plugins/clearkey/hidl/AesCtrDecryptor.cpp
index 0ac879c..e03a896 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/AesCtrDecryptor.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/AesCtrDecryptor.cpp
@@ -26,7 +26,7 @@
namespace android {
namespace hardware {
namespace drm {
-namespace V1_2 {
+namespace V1_4 {
namespace clearkey {
using ::android::hardware::drm::V1_0::SubSample;
@@ -79,7 +79,7 @@
}
} // namespace clearkey
-} // namespace V1_2
+} // namespace V1_4
} // namespace drm
} // namespace hardware
} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/Android.bp b/drm/mediadrm/plugins/clearkey/hidl/Android.bp
index c49d5fe..6c68532 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/Android.bp
+++ b/drm/mediadrm/plugins/clearkey/hidl/Android.bp
@@ -57,6 +57,7 @@
"android.hardware.drm@1.1",
"android.hardware.drm@1.2",
"android.hardware.drm@1.3",
+ "android.hardware.drm@1.4",
"libbase",
"libbinder",
"libcrypto",
@@ -110,18 +111,18 @@
}
cc_binary {
- name: "android.hardware.drm@1.3-service.clearkey",
+ name: "android.hardware.drm@1.4-service.clearkey",
defaults: ["clearkey_service_defaults"],
srcs: ["service.cpp"],
- init_rc: ["android.hardware.drm@1.3-service.clearkey.rc"],
- vintf_fragments: ["manifest_android.hardware.drm@1.3-service.clearkey.xml"],
+ init_rc: ["android.hardware.drm@1.4-service.clearkey.rc"],
+ vintf_fragments: ["manifest_android.hardware.drm@1.4-service.clearkey.xml"],
}
cc_binary {
- name: "android.hardware.drm@1.3-service-lazy.clearkey",
- overrides: ["android.hardware.drm@1.3-service.clearkey"],
+ name: "android.hardware.drm@1.4-service-lazy.clearkey",
+ overrides: ["android.hardware.drm@1.4-service.clearkey"],
defaults: ["clearkey_service_defaults"],
srcs: ["serviceLazy.cpp"],
- init_rc: ["android.hardware.drm@1.3-service-lazy.clearkey.rc"],
- vintf_fragments: ["manifest_android.hardware.drm@1.3-service.clearkey.xml"],
+ init_rc: ["android.hardware.drm@1.4-service-lazy.clearkey.rc"],
+ vintf_fragments: ["manifest_android.hardware.drm@1.4-service.clearkey.xml"],
}
diff --git a/drm/mediadrm/plugins/clearkey/hidl/Base64.cpp b/drm/mediadrm/plugins/clearkey/hidl/Base64.cpp
index 657a42f..d81f875 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/Base64.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/Base64.cpp
@@ -21,7 +21,7 @@
namespace android {
namespace hardware {
namespace drm {
-namespace V1_2 {
+namespace V1_4 {
namespace clearkey {
sp<Buffer> decodeBase64(const std::string &s) {
@@ -169,7 +169,7 @@
}
} // namespace clearkey
-} // namespace V1_2
+} // namespace V1_4
} // namespace drm
} // namespace hardware
} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/Buffer.cpp b/drm/mediadrm/plugins/clearkey/hidl/Buffer.cpp
index 75f8395..dcb76f4 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/Buffer.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/Buffer.cpp
@@ -21,7 +21,7 @@
namespace android {
namespace hardware {
namespace drm {
-namespace V1_2 {
+namespace V1_4 {
namespace clearkey {
Buffer::Buffer(size_t capacity)
@@ -47,7 +47,7 @@
}
} // namespace clearkey
-} // namespace V1_2
+} // namespace V1_4
} // namespace drm
} // namespace hardware
} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/CreatePluginFactories.cpp b/drm/mediadrm/plugins/clearkey/hidl/CreatePluginFactories.cpp
index bfb0e05..4ab33d3 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/CreatePluginFactories.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/CreatePluginFactories.cpp
@@ -22,7 +22,7 @@
namespace android {
namespace hardware {
namespace drm {
-namespace V1_3 {
+namespace V1_4 {
namespace clearkey {
extern "C" {
@@ -38,7 +38,7 @@
} // extern "C"
} // namespace clearkey
-} // namespace V1_3
+} // namespace V1_4
} // namespace drm
} // namespace hardware
} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/CryptoFactory.cpp b/drm/mediadrm/plugins/clearkey/hidl/CryptoFactory.cpp
index a6ed3bd..0bebc3b 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/CryptoFactory.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/CryptoFactory.cpp
@@ -27,11 +27,11 @@
namespace android {
namespace hardware {
namespace drm {
-namespace V1_3 {
+namespace V1_4 {
namespace clearkey {
using ::android::hardware::drm::V1_0::Status;
-using ::android::hardware::drm::V1_2::clearkey::CryptoPlugin;
+using ::android::hardware::drm::V1_4::clearkey::CryptoPlugin;
Return<bool> CryptoFactory::isCryptoSchemeSupported(
const hidl_array<uint8_t, 16> &uuid)
@@ -63,7 +63,7 @@
}
} // namespace clearkey
-} // namespace V1_3
+} // namespace V1_4
} // namespace drm
} // namespace hardware
} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/CryptoPlugin.cpp b/drm/mediadrm/plugins/clearkey/hidl/CryptoPlugin.cpp
index 302dd39..b92f236 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/CryptoPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/CryptoPlugin.cpp
@@ -27,7 +27,7 @@
namespace android {
namespace hardware {
namespace drm {
-namespace V1_2 {
+namespace V1_4 {
namespace clearkey {
using ::android::hardware::drm::V1_0::BufferType;
@@ -236,7 +236,7 @@
}
} // namespace clearkey
-} // namespace V1_2
+} // namespace V1_4.
} // namespace drm
} // namespace hardware
} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/DeviceFiles.cpp b/drm/mediadrm/plugins/clearkey/hidl/DeviceFiles.cpp
index 2415b6f..0385d8f 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/DeviceFiles.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/DeviceFiles.cpp
@@ -38,7 +38,7 @@
namespace android {
namespace hardware {
namespace drm {
-namespace V1_2 {
+namespace V1_4 {
namespace clearkey {
bool DeviceFiles::StoreLicense(
@@ -246,7 +246,7 @@
}
} // namespace clearkey
-} // namespace V1_2
+} // namespace V1_4
} // namespace drm
} // namespace hardware
} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/DrmFactory.cpp b/drm/mediadrm/plugins/clearkey/hidl/DrmFactory.cpp
index 1ce8269..14cb5c1 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/DrmFactory.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/DrmFactory.cpp
@@ -31,13 +31,13 @@
namespace android {
namespace hardware {
namespace drm {
-namespace V1_3 {
+namespace V1_4 {
namespace clearkey {
using ::android::hardware::drm::V1_0::Status;
using ::android::hardware::drm::V1_1::SecurityLevel;
-using ::android::hardware::drm::V1_2::clearkey::DrmPlugin;
-using ::android::hardware::drm::V1_2::clearkey::SessionLibrary;
+using ::android::hardware::drm::V1_4::clearkey::DrmPlugin;
+using ::android::hardware::drm::V1_4::clearkey::SessionLibrary;
using ::android::hardware::Void;
Return<bool> DrmFactory::isCryptoSchemeSupported(
@@ -105,7 +105,7 @@
}
} // namespace clearkey
-} // namespace V1_3
+} // namespace V1_4
} // namespace drm
} // namespace hardware
} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
index 6f69110..4318af4 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
@@ -18,6 +18,7 @@
#define LOG_TAG "hidl_ClearKeyPlugin"
#include <utils/Log.h>
+#include <chrono>
#include <stdio.h>
#include <inttypes.h>
@@ -58,7 +59,7 @@
namespace android {
namespace hardware {
namespace drm {
-namespace V1_2 {
+namespace V1_4 {
namespace clearkey {
KeyRequestType toKeyRequestType_V1_0(KeyRequestType_V1_1 keyRequestType) {
@@ -635,6 +636,68 @@
return Void();
}
+Return<void> DrmPlugin::getLogMessages(
+ getLogMessages_cb _hidl_cb) {
+ using std::chrono::duration_cast;
+ using std::chrono::milliseconds;
+ using std::chrono::system_clock;
+
+ auto timeMillis = duration_cast<milliseconds>(
+ system_clock::now().time_since_epoch()).count();
+
+ //TODO(b/182525516) Stub out for now
+ std::vector<LogMessage> logs = {
+ { timeMillis, LogPriority::DEFAULT, std::string() }};
+ _hidl_cb(drm::V1_4::Status::OK, toHidlVec(logs));
+ return Void();
+}
+
+Return<bool> DrmPlugin::requiresSecureDecoder(
+ const hidl_string& mime, SecurityLevel level) {
+ if (!strncasecmp(mime.c_str(), "video/", 6)) {
+ // Type is video, so check level to see if we require a secure decoder.
+ return level == SecurityLevel::HW_SECURE_DECODE;
+ } else {
+ // Type is not video, so never require a secure decoder.
+ return false;
+ }
+}
+
+Return<bool> DrmPlugin::requiresSecureDecoderDefault(const hidl_string& mime) {
+ UNUSED(mime);
+ // Clearkey only supports SW_SECURE_CRYPTO, so we always returns false
+ // regardless of mime type.
+ return false;
+}
+
+Return<Status> DrmPlugin::setPlaybackId(
+ const hidl_vec<uint8_t>& sessionId,
+ const hidl_string& playbackId) {
+ if (sessionId.size() == 0) {
+ ALOGE("Invalid empty session id");
+ return Status::BAD_VALUE;
+ }
+
+ std::vector<uint8_t> sid = toVector(sessionId);
+ sp<Session> session = mSessionLibrary->findSession(sid);
+ if (!session.get()) {
+ return Status::ERROR_DRM_SESSION_NOT_OPENED;
+ }
+
+ std::map<std::vector<uint8_t>, std::string>::iterator itr =
+ mPlaybackId.find(sid);
+ if (itr != mPlaybackId.end()) {
+ mPlaybackId[sid] = playbackId;
+ } else {
+ if (!mPlaybackId.insert(
+ std::pair<std::vector<uint8_t>, std::string>(sid, playbackId)).second) {
+ ALOGE("Failed to set playback Id");
+ return Status::ERROR_DRM_UNKNOWN;
+ }
+ }
+ return Status::OK;
+}
+
Return<Status> DrmPlugin::setSecurityLevel(const hidl_vec<uint8_t>& sessionId,
SecurityLevel level) {
if (sessionId.size() == 0) {
@@ -702,8 +765,21 @@
"close_session", { closeSessionNotOpenedAttribute }, { closeSessionNotOpenedMetricValue }
};
- DrmMetricGroup metrics = { { openSessionMetric, closeSessionMetric,
- closeSessionNotOpenedMetric } };
+ // Set the setPlaybackId metric.
+ DrmMetricGroup::Attribute setPlaybackIdOKAttribute = {
+ "status", DrmMetricGroup::ValueType::INT64_TYPE,
+ (int64_t) Status::OK, 0.0, ""
+ };
+ std::string playbackId = mPlaybackId.begin()->second;
+ DrmMetricGroup::Value setPlaybackIdMetricValue = {
+ "value", DrmMetricGroup::ValueType::STRING_TYPE, 0, 0, playbackId.c_str()
+ };
+ DrmMetricGroup::Metric setPlaybackIdMetric = {
+ "set_playback_id", { setPlaybackIdOKAttribute }, { setPlaybackIdMetricValue }
+ };
+
+ DrmMetricGroup metrics = {{ openSessionMetric, closeSessionMetric,
+ closeSessionNotOpenedMetric, setPlaybackIdMetric }};
_hidl_cb(Status::OK, hidl_vec<DrmMetricGroup>({metrics}));
return Void();
@@ -907,7 +983,7 @@
}
} // namespace clearkey
-} // namespace V1_2
+} // namespace V1_4
} // namespace drm
} // namespace hardware
} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/InitDataParser.cpp b/drm/mediadrm/plugins/clearkey/hidl/InitDataParser.cpp
index 8513434..eccc843 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/InitDataParser.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/InitDataParser.cpp
@@ -31,7 +31,7 @@
namespace android {
namespace hardware {
namespace drm {
-namespace V1_2 {
+namespace V1_4 {
namespace clearkey {
namespace {
@@ -180,7 +180,7 @@
}
} // namespace clearkey
-} // namespace V1_2
+} // namespace V1_4
} // namespace drm
} // namespace hardware
} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/JsonWebKey.cpp b/drm/mediadrm/plugins/clearkey/hidl/JsonWebKey.cpp
index 99668a7..45cc775 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/JsonWebKey.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/JsonWebKey.cpp
@@ -36,7 +36,7 @@
namespace android {
namespace hardware {
namespace drm {
-namespace V1_2 {
+namespace V1_4 {
namespace clearkey {
JsonWebKey::JsonWebKey() {
@@ -271,7 +271,7 @@
}
} // namespace clearkey
-} // namespace V1_2
+} // namespace V1_4
} // namespace drm
} // namespace hardware
} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/MemoryFileSystem.cpp b/drm/mediadrm/plugins/clearkey/hidl/MemoryFileSystem.cpp
index 32cf2dc..e61db3f 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/MemoryFileSystem.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/MemoryFileSystem.cpp
@@ -11,7 +11,7 @@
namespace android {
namespace hardware {
namespace drm {
-namespace V1_2 {
+namespace V1_4 {
namespace clearkey {
std::string MemoryFileSystem::GetFileName(const std::string& path) {
@@ -93,7 +93,7 @@
}
} // namespace clearkey
-} // namespace V1_2
+} // namespace V1_4
} // namespace drm
} // namespace hardware
} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/Session.cpp b/drm/mediadrm/plugins/clearkey/hidl/Session.cpp
index a9d7016..cf668d4 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/Session.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/Session.cpp
@@ -28,7 +28,7 @@
namespace android {
namespace hardware {
namespace drm {
-namespace V1_2 {
+namespace V1_4 {
namespace clearkey {
using ::android::hardware::drm::V1_0::KeyValue;
@@ -95,7 +95,7 @@
}
} // namespace clearkey
-} // namespace V1_2
+} // namespace V1_4
} // namespace drm
} // namespace hardware
} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/SessionLibrary.cpp b/drm/mediadrm/plugins/clearkey/hidl/SessionLibrary.cpp
index 99fb30f..88afcc4 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/SessionLibrary.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/SessionLibrary.cpp
@@ -24,7 +24,7 @@
namespace android {
namespace hardware {
namespace drm {
-namespace V1_2 {
+namespace V1_4 {
namespace clearkey {
using ::android::hardware::hidl_string;
@@ -86,7 +86,7 @@
}
} // namespace clearkey
-} // namespace V1_2
+} // namespace V1_4
} // namespace drm
} // namespace hardware
} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.4-service-lazy.clearkey.rc b/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.4-service-lazy.clearkey.rc
new file mode 100644
index 0000000..46aba88
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.4-service-lazy.clearkey.rc
@@ -0,0 +1,18 @@
+service vendor.drm-clearkey-hal-1-4 /vendor/bin/hw/android.hardware.drm@1.4-service-lazy.clearkey
+ interface android.hardware.drm@1.0::ICryptoFactory clearkey
+ interface android.hardware.drm@1.0::IDrmFactory clearkey
+ interface android.hardware.drm@1.1::ICryptoFactory clearkey
+ interface android.hardware.drm@1.1::IDrmFactory clearkey
+ interface android.hardware.drm@1.2::ICryptoFactory clearkey
+ interface android.hardware.drm@1.2::IDrmFactory clearkey
+ interface android.hardware.drm@1.3::ICryptoFactory clearkey
+ interface android.hardware.drm@1.3::IDrmFactory clearkey
+ interface android.hardware.drm@1.4::ICryptoFactory clearkey
+ interface android.hardware.drm@1.4::IDrmFactory clearkey
+ disabled
+ oneshot
+ class hal
+ user media
+ group media mediadrm
+ ioprio rt 4
+ writepid /dev/cpuset/foreground/tasks
diff --git a/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.4-service.clearkey.rc b/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.4-service.clearkey.rc
new file mode 100644
index 0000000..8186933
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.4-service.clearkey.rc
@@ -0,0 +1,16 @@
+service vendor.drm-clearkey-hal-1-4 /vendor/bin/hw/android.hardware.drm@1.4-service.clearkey
+ interface android.hardware.drm@1.0::ICryptoFactory clearkey
+ interface android.hardware.drm@1.0::IDrmFactory clearkey
+ interface android.hardware.drm@1.1::ICryptoFactory clearkey
+ interface android.hardware.drm@1.1::IDrmFactory clearkey
+ interface android.hardware.drm@1.2::ICryptoFactory clearkey
+ interface android.hardware.drm@1.2::IDrmFactory clearkey
+ interface android.hardware.drm@1.3::ICryptoFactory clearkey
+ interface android.hardware.drm@1.3::IDrmFactory clearkey
+ interface android.hardware.drm@1.4::ICryptoFactory clearkey
+ interface android.hardware.drm@1.4::IDrmFactory clearkey
+ class hal
+ user media
+ group media mediadrm
+ ioprio rt 4
+ writepid /dev/cpuset/foreground/tasks
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/AesCtrDecryptor.h b/drm/mediadrm/plugins/clearkey/hidl/include/AesCtrDecryptor.h
index 721f4c0..97794f7 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/AesCtrDecryptor.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/AesCtrDecryptor.h
@@ -22,7 +22,7 @@
namespace android {
namespace hardware {
namespace drm {
-namespace V1_2 {
+namespace V1_4 {
namespace clearkey {
using ::android::hardware::drm::V1_0::Status;
@@ -42,7 +42,7 @@
};
} // namespace clearkey
-} // namespace V1_2
+} // namespace V1_4
} // namespace drm
} // namespace hardware
} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/Base64.h b/drm/mediadrm/plugins/clearkey/hidl/include/Base64.h
index ec30cc1..2349f23 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/Base64.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/Base64.h
@@ -25,7 +25,7 @@
namespace android {
namespace hardware {
namespace drm {
-namespace V1_2 {
+namespace V1_4 {
namespace clearkey {
using ::android::sp;
@@ -38,7 +38,7 @@
void encodeBase64Url(const void *data, size_t size, std::string *out);
} // namespace clearkey
-} // namespace V1_2
+} // namespace V1_4
} // namespace drm
} // namespace hardware
} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/Buffer.h b/drm/mediadrm/plugins/clearkey/hidl/include/Buffer.h
index c497e37..66aaa73 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/Buffer.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/Buffer.h
@@ -25,7 +25,7 @@
namespace android {
namespace hardware {
namespace drm {
-namespace V1_2 {
+namespace V1_4 {
namespace clearkey {
using ::android::sp;
@@ -54,7 +54,7 @@
};
} // namespace clearkey
-} // namespace V1_2
+} // namespace V1_4
} // namespace drm
} // namespace hardware
} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyDrmProperties.h b/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyDrmProperties.h
index b83ce69..8e47c45 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyDrmProperties.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyDrmProperties.h
@@ -22,7 +22,7 @@
namespace android {
namespace hardware {
namespace drm {
-namespace V1_2 {
+namespace V1_4 {
namespace clearkey {
static const std::string kVendorKey("vendor");
@@ -55,7 +55,7 @@
static const uint8_t kMetricsData[] = { 0 };
} // namespace clearkey
-} // namespace V1_2
+} // namespace V1_4
} // namespace drm
} // namespace hardware
} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyTypes.h b/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyTypes.h
index 03c434e..cd18029 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyTypes.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyTypes.h
@@ -24,7 +24,7 @@
namespace android {
namespace hardware {
namespace drm {
-namespace V1_2 {
+namespace V1_4 {
namespace clearkey {
using ::android::hardware::drm::V1_0::KeyValue;
@@ -48,7 +48,7 @@
void operator=(const TypeName&) = delete;
} // namespace clearkey
-} // namespace V1_2
+} // namespace V1_4
} // namespace drm
} // namespace hardware
} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/CreatePluginFactories.h b/drm/mediadrm/plugins/clearkey/hidl/include/CreatePluginFactories.h
index c1c188e..d4a8a17 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/CreatePluginFactories.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/CreatePluginFactories.h
@@ -17,17 +17,17 @@
#ifndef CLEARKEY_CREATE_PLUGIN_FACTORIES_H_
#define CLEARKEY_CREATE_PLUGIN_FACTORIES_H_
-#include <android/hardware/drm/1.3/ICryptoFactory.h>
-#include <android/hardware/drm/1.3/IDrmFactory.h>
+#include <android/hardware/drm/1.4/ICryptoFactory.h>
+#include <android/hardware/drm/1.4/IDrmFactory.h>
namespace android {
namespace hardware {
namespace drm {
-namespace V1_3 {
+namespace V1_4 {
namespace clearkey {
-using ::android::hardware::drm::V1_3::ICryptoFactory;
-using ::android::hardware::drm::V1_3::IDrmFactory;
+using ::android::hardware::drm::V1_4::ICryptoFactory;
+using ::android::hardware::drm::V1_4::IDrmFactory;
extern "C" {
IDrmFactory* createDrmFactory();
@@ -35,7 +35,7 @@
}
} // namespace clearkey
-} // namespace V1_3
+} // namespace V1_4
} // namespace drm
} // namespace hardware
} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/CryptoFactory.h b/drm/mediadrm/plugins/clearkey/hidl/include/CryptoFactory.h
index cb4811b..e6b541f 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/CryptoFactory.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/CryptoFactory.h
@@ -18,17 +18,17 @@
#define CLEARKEY_CRYPTO_FACTORY_H_
#include <android/hardware/drm/1.0/ICryptoPlugin.h>
-#include <android/hardware/drm/1.3/ICryptoFactory.h>
+#include <android/hardware/drm/1.4/ICryptoFactory.h>
#include "ClearKeyTypes.h"
namespace android {
namespace hardware {
namespace drm {
-namespace V1_3 {
+namespace V1_4 {
namespace clearkey {
-using ::android::hardware::drm::V1_3::ICryptoFactory;
+using ::android::hardware::drm::V1_4::ICryptoFactory;
using ::android::hardware::drm::V1_0::ICryptoPlugin;
using ::android::hardware::hidl_array;
using ::android::hardware::hidl_string;
@@ -52,7 +52,7 @@
};
} // namespace clearkey
-} // namespace V1_3
+} // namespace V1_4
} // namespace drm
} // namespace hardware
} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/CryptoPlugin.h b/drm/mediadrm/plugins/clearkey/hidl/include/CryptoPlugin.h
index 23a64fa..a7b2427 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/CryptoPlugin.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/CryptoPlugin.h
@@ -34,7 +34,7 @@
namespace android {
namespace hardware {
namespace drm {
-namespace V1_2 {
+namespace V1_4 {
namespace clearkey {
namespace drm = ::android::hardware::drm;
@@ -114,7 +114,7 @@
};
} // namespace clearkey
-} // namespace V1_2
+} // namespace V1_4
} // namespace drm
} // namespace hardware
} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/DeviceFiles.h b/drm/mediadrm/plugins/clearkey/hidl/include/DeviceFiles.h
index 554ae59..6466ac3 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/DeviceFiles.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/DeviceFiles.h
@@ -20,9 +20,11 @@
namespace android {
namespace hardware {
namespace drm {
-namespace V1_2 {
+namespace V1_4 {
namespace clearkey {
+using ::android::hardware::drm::V1_2::clearkey::OfflineFile;
+
class DeviceFiles {
public:
typedef enum {
@@ -63,7 +65,7 @@
};
} // namespace clearkey
-} // namespace V1_2
+} // namespace V1_4
} // namespace drm
} // namespace hardware
} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/DrmFactory.h b/drm/mediadrm/plugins/clearkey/hidl/include/DrmFactory.h
index 63234cf..fea1ec8 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/DrmFactory.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/DrmFactory.h
@@ -17,15 +17,15 @@
#ifndef CLEARKEY_DRM_FACTORY_H_
#define CLEARKEY_DRM_FACTORY_H_
-#include <android/hardware/drm/1.2/IDrmPlugin.h>
-#include <android/hardware/drm/1.3/IDrmFactory.h>
+#include <android/hardware/drm/1.4/IDrmPlugin.h>
+#include <android/hardware/drm/1.4/IDrmFactory.h>
#include "ClearKeyTypes.h"
namespace android {
namespace hardware {
namespace drm {
-namespace V1_3 {
+namespace V1_4 {
namespace clearkey {
using ::android::hardware::drm::V1_1::SecurityLevel;
@@ -63,7 +63,7 @@
};
} // namespace clearkey
-} // namespace V1_3
+} // namespace V1_4
} // namespace drm
} // namespace hardware
} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h b/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
index 894985b..5d6e3da 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
@@ -17,7 +17,7 @@
#ifndef CLEARKEY_DRM_PLUGIN_H_
#define CLEARKEY_DRM_PLUGIN_H_
-#include <android/hardware/drm/1.2/IDrmPlugin.h>
+#include <android/hardware/drm/1.4/IDrmPlugin.h>
#include <android/hardware/drm/1.2/IDrmPluginListener.h>
#include <map>
@@ -32,7 +32,7 @@
namespace android {
namespace hardware {
namespace drm {
-namespace V1_2 {
+namespace V1_4 {
namespace clearkey {
namespace drm = ::android::hardware::drm;
@@ -50,9 +50,12 @@
using drm::V1_1::HdcpLevel;
using drm::V1_1::SecureStopRelease;
using drm::V1_1::SecurityLevel;
-using drm::V1_2::IDrmPlugin;
using drm::V1_2::KeySetId;
using drm::V1_2::OfflineLicenseState;
+using drm::V1_4::clearkey::DeviceFiles;
+using drm::V1_4::clearkey::Session;
+using drm::V1_4::clearkey::SessionLibrary;
+using drm::V1_4::IDrmPlugin;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
@@ -199,6 +202,18 @@
Return<Status> setPropertyByteArray(
const hidl_string& name, const hidl_vec<uint8_t>& value) override;
+ Return<void> getLogMessages(
+ getLogMessages_cb _hidl_cb) override;
+
+ Return<Status> setPlaybackId(
+ const hidl_vec<uint8_t>& sessionId,
+ const hidl_string& playbackId) override;
+
+ Return<bool> requiresSecureDecoder(
+ const hidl_string& mime, SecurityLevel level) override;
+
+ Return<bool> requiresSecureDecoderDefault(const hidl_string& mime) override;
+
Return<Status> setCipherAlgorithm(
const hidl_vec<uint8_t>& sessionId, const hidl_string& algorithm) {
if (sessionId.size() == 0 || algorithm.size() == 0) {
@@ -398,6 +413,7 @@
std::map<std::string, std::string> mStringProperties;
std::map<std::string, std::vector<uint8_t> > mByteArrayProperties;
std::map<std::string, std::vector<uint8_t> > mReleaseKeysMap;
+ std::map<std::vector<uint8_t>, std::string> mPlaybackId;
std::map<std::vector<uint8_t>, SecurityLevel> mSecurityLevel;
sp<IDrmPluginListener> mListener;
sp<IDrmPluginListener_V1_2> mListenerV1_2;
@@ -424,7 +440,7 @@
};
} // namespace clearkey
-} // namespace V1_2
+} // namespace V1_4
} // namespace drm
} // namespace hardware
} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/InitDataParser.h b/drm/mediadrm/plugins/clearkey/hidl/include/InitDataParser.h
index 889f511..59338c9 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/InitDataParser.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/InitDataParser.h
@@ -24,7 +24,7 @@
namespace android {
namespace hardware {
namespace drm {
-namespace V1_2 {
+namespace V1_4 {
namespace clearkey {
using ::android::hardware::drm::V1_0::Status;
@@ -49,7 +49,7 @@
};
} // namespace clearkey
-} // namespace V1_2
+} // namespace V1_4
} // namespace drm
} // namespace hardware
} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/JsonWebKey.h b/drm/mediadrm/plugins/clearkey/hidl/include/JsonWebKey.h
index e57470c..40a2d74 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/JsonWebKey.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/JsonWebKey.h
@@ -23,7 +23,7 @@
namespace android {
namespace hardware {
namespace drm {
-namespace V1_2 {
+namespace V1_4 {
namespace clearkey {
class JsonWebKey {
@@ -54,7 +54,7 @@
};
} // namespace clearkey
-} // namespace V1_2
+} // namespace V1_4
} // namespace drm
} // namespace hardware
} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/MemoryFileSystem.h b/drm/mediadrm/plugins/clearkey/hidl/include/MemoryFileSystem.h
index 6ac0e2c..a90d818 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/MemoryFileSystem.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/MemoryFileSystem.h
@@ -15,7 +15,7 @@
namespace android {
namespace hardware {
namespace drm {
-namespace V1_2 {
+namespace V1_4 {
namespace clearkey {
// Using android file system requires clearkey plugin to update
@@ -64,7 +64,7 @@
};
} // namespace clearkey
-} // namespace V1_2
+} // namespace V1_4
} // namespace drm
} // namespace hardware
} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/Session.h b/drm/mediadrm/plugins/clearkey/hidl/include/Session.h
index a159e5a..05cb8c8 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/Session.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/Session.h
@@ -27,7 +27,7 @@
namespace android {
namespace hardware {
namespace drm {
-namespace V1_2 {
+namespace V1_4 {
namespace clearkey {
namespace drm = ::android::hardware::drm;
@@ -73,7 +73,7 @@
};
} // namespace clearkey
-} // namespace V1_2
+} // namespace V1_4
} // namespace drm
} // namespace hardware
} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/SessionLibrary.h b/drm/mediadrm/plugins/clearkey/hidl/include/SessionLibrary.h
index 1e567b8..5e77438 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/SessionLibrary.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/SessionLibrary.h
@@ -26,7 +26,7 @@
namespace android {
namespace hardware {
namespace drm {
-namespace V1_2 {
+namespace V1_4 {
namespace clearkey {
using ::android::sp;
@@ -58,7 +58,7 @@
};
} // namespace clearkey
-} // namespace V1_2
+} // namespace V1_4
} // namespace drm
} // namespace hardware
} // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/TypeConvert.h b/drm/mediadrm/plugins/clearkey/hidl/include/TypeConvert.h
index b0f8607..22eeccd 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/TypeConvert.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/TypeConvert.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef CLEARKEY_ANDROID_HARDWARE_DRM_V1_1_TYPECONVERT
-#define CLEARKEY_ANDROID_HARDWARE_DRM_V1_1_TYPECONVERT
+#ifndef CLEARKEY_ANDROID_HARDWARE_DRM_V1_4_TYPECONVERT
+#define CLEARKEY_ANDROID_HARDWARE_DRM_V1_4_TYPECONVERT
#include <vector>
@@ -24,7 +24,7 @@
namespace android {
namespace hardware {
namespace drm {
-namespace V1_2 {
+namespace V1_4 {
namespace clearkey {
using ::android::hardware::hidl_array;
@@ -80,9 +80,9 @@
}
} // namespace clearkey
-} // namespace V1_2
+} // namespace V1_4
} // namespace drm
} // namespace hardware
} // namespace android
-#endif // CLEARKEY_ANDROID_HARDWARE_DRM_V1_1_TYPECONVERT
+#endif // CLEARKEY_ANDROID_HARDWARE_DRM_V1_4_TYPECONVERT
diff --git a/drm/mediadrm/plugins/clearkey/hidl/manifest_android.hardware.drm@1.4-service.clearkey.xml b/drm/mediadrm/plugins/clearkey/hidl/manifest_android.hardware.drm@1.4-service.clearkey.xml
new file mode 100644
index 0000000..31ddb5f
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/manifest_android.hardware.drm@1.4-service.clearkey.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<manifest version="1.0" type="device">
+ <hal format="hidl">
+ <name>android.hardware.drm</name>
+ <transport>hwbinder</transport>
+ <fqname>@1.4::ICryptoFactory/clearkey</fqname>
+ <fqname>@1.4::IDrmFactory/clearkey</fqname>
+ </hal>
+</manifest>
diff --git a/drm/mediadrm/plugins/clearkey/hidl/service.cpp b/drm/mediadrm/plugins/clearkey/hidl/service.cpp
index b62baae..d3d6905 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/service.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/service.cpp
@@ -25,10 +25,10 @@
using ::android::hardware::joinRpcThreadpool;
using ::android::sp;
-using android::hardware::drm::V1_3::ICryptoFactory;
-using android::hardware::drm::V1_3::IDrmFactory;
-using android::hardware::drm::V1_3::clearkey::CryptoFactory;
-using android::hardware::drm::V1_3::clearkey::DrmFactory;
+using android::hardware::drm::V1_4::ICryptoFactory;
+using android::hardware::drm::V1_4::IDrmFactory;
+using android::hardware::drm::V1_4::clearkey::CryptoFactory;
+using android::hardware::drm::V1_4::clearkey::DrmFactory;
int main(int /* argc */, char** /* argv */) {
sp<IDrmFactory> drmFactory = new DrmFactory;
diff --git a/drm/mediadrm/plugins/clearkey/hidl/serviceLazy.cpp b/drm/mediadrm/plugins/clearkey/hidl/serviceLazy.cpp
index b3e0179..358b5cc 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/serviceLazy.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/serviceLazy.cpp
@@ -25,10 +25,10 @@
using ::android::hardware::joinRpcThreadpool;
using ::android::sp;
-using android::hardware::drm::V1_3::ICryptoFactory;
-using android::hardware::drm::V1_3::IDrmFactory;
-using android::hardware::drm::V1_3::clearkey::CryptoFactory;
-using android::hardware::drm::V1_3::clearkey::DrmFactory;
+using android::hardware::drm::V1_4::ICryptoFactory;
+using android::hardware::drm::V1_4::IDrmFactory;
+using android::hardware::drm::V1_4::clearkey::CryptoFactory;
+using android::hardware::drm::V1_4::clearkey::DrmFactory;
using android::hardware::LazyServiceRegistrar;
int main(int /* argc */, char** /* argv */) {
diff --git a/media/bufferpool/2.0/BufferPoolClient.cpp b/media/bufferpool/2.0/BufferPoolClient.cpp
index 9308b81..cda23ff 100644
--- a/media/bufferpool/2.0/BufferPoolClient.cpp
+++ b/media/bufferpool/2.0/BufferPoolClient.cpp
@@ -29,7 +29,7 @@
namespace V2_0 {
namespace implementation {
-static constexpr int64_t kReceiveTimeoutUs = 1000000; // 100ms
+static constexpr int64_t kReceiveTimeoutUs = 2000000; // 2s
static constexpr int kPostMaxRetry = 3;
static constexpr int kCacheTtlUs = 1000000; // TODO: tune
static constexpr size_t kMaxCachedBufferCount = 64;
diff --git a/media/codec2/components/avc/C2SoftAvcEnc.cpp b/media/codec2/components/avc/C2SoftAvcEnc.cpp
index fc5b75d..bab651f 100644
--- a/media/codec2/components/avc/C2SoftAvcEnc.cpp
+++ b/media/codec2/components/avc/C2SoftAvcEnc.cpp
@@ -454,19 +454,11 @@
} // namespace
-static IV_COLOR_FORMAT_T GetIvColorFormat() {
- static IV_COLOR_FORMAT_T sColorFormat =
- (GetYuv420FlexibleLayout() == FLEX_LAYOUT_SEMIPLANAR_UV) ? IV_YUV_420SP_UV :
- (GetYuv420FlexibleLayout() == FLEX_LAYOUT_SEMIPLANAR_VU) ? IV_YUV_420SP_VU :
- IV_YUV_420P;
- return sColorFormat;
-}
-
C2SoftAvcEnc::C2SoftAvcEnc(
const char *name, c2_node_id_t id, const std::shared_ptr<IntfImpl> &intfImpl)
: SimpleC2Component(std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
mIntf(intfImpl),
- mIvVideoColorFormat(GetIvColorFormat()),
+ mIvVideoColorFormat(IV_YUV_420P),
mAVCEncProfile(IV_PROFILE_BASE),
mAVCEncLevel(41),
mStarted(false),
@@ -1034,7 +1026,8 @@
// Assume worst case output buffer size to be equal to number of bytes in input
mOutBufferSize = std::max(width * height * 3 / 2, kMinOutBufferSize);
- mIvVideoColorFormat = GetIvColorFormat();
+ // TODO
+ mIvVideoColorFormat = IV_YUV_420P;
ALOGD("Params width %d height %d level %d colorFormat %d bframes %d", width,
height, mAVCEncLevel, mIvVideoColorFormat, mBframes);
@@ -1332,6 +1325,7 @@
mSize->width, input->height(), mSize->height);
return C2_BAD_VALUE;
}
+ ALOGV("width = %d, height = %d", input->width(), input->height());
const C2PlanarLayout &layout = input->layout();
uint8_t *yPlane = const_cast<uint8_t *>(input->data()[C2PlanarLayout::PLANE_Y]);
uint8_t *uPlane = const_cast<uint8_t *>(input->data()[C2PlanarLayout::PLANE_U]);
@@ -1368,8 +1362,7 @@
return C2_BAD_VALUE;
}
- if (mIvVideoColorFormat == IV_YUV_420P
- && layout.planes[layout.PLANE_Y].colInc == 1
+ if (layout.planes[layout.PLANE_Y].colInc == 1
&& layout.planes[layout.PLANE_U].colInc == 1
&& layout.planes[layout.PLANE_V].colInc == 1
&& uStride == vStride
@@ -1377,61 +1370,21 @@
// I420 compatible - already set up above
break;
}
- if (mIvVideoColorFormat == IV_YUV_420SP_UV
- && layout.planes[layout.PLANE_Y].colInc == 1
- && layout.planes[layout.PLANE_U].colInc == 2
- && layout.planes[layout.PLANE_V].colInc == 2
- && uStride == vStride
- && yStride == vStride
- && uPlane + 1 == vPlane) {
- // NV12 compatible - already set up above
- break;
- }
- if (mIvVideoColorFormat == IV_YUV_420SP_VU
- && layout.planes[layout.PLANE_Y].colInc == 1
- && layout.planes[layout.PLANE_U].colInc == 2
- && layout.planes[layout.PLANE_V].colInc == 2
- && uStride == vStride
- && yStride == vStride
- && uPlane == vPlane + 1) {
- // NV21 compatible - already set up above
- break;
- }
// copy to I420
yStride = width;
uStride = vStride = yStride / 2;
MemoryBlock conversionBuffer = mConversionBuffers.fetch(yPlaneSize * 3 / 2);
mConversionBuffersInUse.emplace(conversionBuffer.data(), conversionBuffer);
- MediaImage2 img;
- switch (mIvVideoColorFormat) {
- case IV_YUV_420P:
- img = CreateYUV420PlanarMediaImage2(width, height, yStride, height);
- yPlane = conversionBuffer.data();
- uPlane = yPlane + yPlaneSize;
- vPlane = uPlane + yPlaneSize / 4;
- break;
- case IV_YUV_420SP_VU:
- img = CreateYUV420SemiPlanarMediaImage2(width, height, yStride, height);
- img.mPlane[MediaImage2::U].mOffset++;
- img.mPlane[MediaImage2::V].mOffset--;
- yPlane = conversionBuffer.data();
- vPlane = yPlane + yPlaneSize;
- uPlane = vPlane + 1;
- break;
- case IV_YUV_420SP_UV:
- default:
- img = CreateYUV420SemiPlanarMediaImage2(width, height, yStride, height);
- yPlane = conversionBuffer.data();
- uPlane = yPlane + yPlaneSize;
- vPlane = uPlane + 1;
- break;
- }
+ MediaImage2 img = CreateYUV420PlanarMediaImage2(width, height, yStride, height);
status_t err = ImageCopy(conversionBuffer.data(), &img, *input);
if (err != OK) {
ALOGE("Buffer conversion failed: %d", err);
return C2_BAD_VALUE;
}
+ yPlane = conversionBuffer.data();
+ uPlane = yPlane + yPlaneSize;
+ vPlane = uPlane + yPlaneSize / 4;
break;
}
@@ -1477,17 +1430,15 @@
break;
}
- case IV_YUV_420SP_VU:
- uPlane = vPlane;
- [[fallthrough]];
case IV_YUV_420SP_UV:
+ case IV_YUV_420SP_VU:
default:
{
ps_inp_raw_buf->apv_bufs[0] = yPlane;
ps_inp_raw_buf->apv_bufs[1] = uPlane;
ps_inp_raw_buf->au4_wd[0] = mSize->width;
- ps_inp_raw_buf->au4_wd[1] = mSize->width / 2;
+ ps_inp_raw_buf->au4_wd[1] = mSize->width;
ps_inp_raw_buf->au4_ht[0] = mSize->height;
ps_inp_raw_buf->au4_ht[1] = mSize->height / 2;
diff --git a/media/codec2/components/base/SimpleC2Component.cpp b/media/codec2/components/base/SimpleC2Component.cpp
index fb3fbd0..dfad226 100644
--- a/media/codec2/components/base/SimpleC2Component.cpp
+++ b/media/codec2/components/base/SimpleC2Component.cpp
@@ -110,17 +110,20 @@
}
case kWhatStop: {
int32_t err = thiz->onStop();
+ thiz->mOutputBlockPool.reset();
Reply(msg, &err);
break;
}
case kWhatReset: {
thiz->onReset();
+ thiz->mOutputBlockPool.reset();
mRunning = false;
Reply(msg);
break;
}
case kWhatRelease: {
thiz->onRelease();
+ thiz->mOutputBlockPool.reset();
mRunning = false;
Reply(msg);
break;
diff --git a/media/codec2/components/raw/C2SoftRawDec.cpp b/media/codec2/components/raw/C2SoftRawDec.cpp
index 31ca705..a03d4e2 100644
--- a/media/codec2/components/raw/C2SoftRawDec.cpp
+++ b/media/codec2/components/raw/C2SoftRawDec.cpp
@@ -87,7 +87,9 @@
.withFields({C2F(mPcmEncodingInfo, value).oneOf({
C2Config::PCM_16,
C2Config::PCM_8,
- C2Config::PCM_FLOAT})
+ C2Config::PCM_FLOAT,
+ C2Config::PCM_24,
+ C2Config::PCM_32})
})
.withSetter((Setter<decltype(*mPcmEncodingInfo)>::StrictValueWithNoDeps))
.build());
diff --git a/media/codec2/core/include/C2Config.h b/media/codec2/core/include/C2Config.h
index f8aa672..6176646 100644
--- a/media/codec2/core/include/C2Config.h
+++ b/media/codec2/core/include/C2Config.h
@@ -75,6 +75,10 @@
enum tiling_mode_t : uint32_t; ///< tiling modes
};
+struct C2PlatformConfig {
+ enum encoding_quality_level_t : uint32_t; ///< encoding quality level
+};
+
namespace {
enum C2ParamIndexKind : C2Param::type_index_t {
@@ -259,7 +263,11 @@
kParamIndexTunnelHandle, // int32[]
kParamIndexTunnelSystemTime, // int64
+ // dmabuf allocator
kParamIndexStoreDmaBufUsage, // store, struct
+
+ // encoding quality requirements
+ kParamIndexEncodingQualityLevel, // encoders, enum
};
}
@@ -394,6 +402,7 @@
_C2_PL_VP9_BASE = 0x7000,
_C2_PL_DV_BASE = 0x8000,
_C2_PL_AV1_BASE = 0x9000,
+ _C2_PL_VP8_BASE = 0xA000,
C2_PROFILE_LEVEL_VENDOR_START = 0x70000000,
};
@@ -547,6 +556,12 @@
PROFILE_AV1_0 = _C2_PL_AV1_BASE, ///< AV1 Profile 0 (4:2:0, 8 to 10 bit)
PROFILE_AV1_1, ///< AV1 Profile 1 (8 to 10 bit)
PROFILE_AV1_2, ///< AV1 Profile 2 (8 to 12 bit)
+
+ // VP8 profiles
+ PROFILE_VP8_0 = _C2_PL_VP8_BASE, ///< VP8 Profile 0
+ PROFILE_VP8_1, ///< VP8 Profile 1
+ PROFILE_VP8_2, ///< VP8 Profile 2
+ PROFILE_VP8_3, ///< VP8 Profile 3
};
enum C2Config::level_t : uint32_t {
@@ -1901,7 +1916,9 @@
C2ENUM(C2Config::pcm_encoding_t, uint32_t,
PCM_16,
PCM_8,
- PCM_FLOAT
+ PCM_FLOAT,
+ PCM_24,
+ PCM_32
)
typedef C2StreamParam<C2Info, C2SimpleValueStruct<C2Config::pcm_encoding_t>, kParamIndexPcmEncoding>
@@ -2331,6 +2348,23 @@
C2PortTunnelSystemTime;
constexpr char C2_PARAMKEY_OUTPUT_RENDER_TIME[] = "output.render-time";
+C2ENUM(C2PlatformConfig::encoding_quality_level_t, uint32_t,
+ NONE,
+ S_HANDHELD,
+ S_HANDHELD_PC
+);
+
+namespace android {
+
+/**
+ * Encoding quality level signaling.
+ */
+typedef C2GlobalParam<C2Setting,
+ C2SimpleValueStruct<C2EasyEnum<C2PlatformConfig::encoding_quality_level_t>>,
+ kParamIndexEncodingQualityLevel> C2EncodingQualityLevel;
+
+}
+
/// @}
#endif // C2CONFIG_H_
diff --git a/media/codec2/hidl/client/client.cpp b/media/codec2/hidl/client/client.cpp
index d49141c..71857e0 100644
--- a/media/codec2/hidl/client/client.cpp
+++ b/media/codec2/hidl/client/client.cpp
@@ -1482,7 +1482,8 @@
c2_status_t Codec2Client::Component::setOutputSurface(
C2BlockPool::local_id_t blockPoolId,
const sp<IGraphicBufferProducer>& surface,
- uint32_t generation) {
+ uint32_t generation,
+ int maxDequeueCount) {
uint64_t bqId = 0;
sp<IGraphicBufferProducer> nullIgbp;
sp<HGraphicBufferProducer2> nullHgbp;
@@ -1496,14 +1497,15 @@
std::shared_ptr<SurfaceSyncObj> syncObj;
if (!surface) {
- mOutputBufferQueue->configure(nullIgbp, generation, 0, nullptr);
+ mOutputBufferQueue->configure(nullIgbp, generation, 0, maxDequeueCount, nullptr);
} else if (surface->getUniqueId(&bqId) != OK) {
LOG(ERROR) << "setOutputSurface -- "
"cannot obtain bufferqueue id.";
bqId = 0;
- mOutputBufferQueue->configure(nullIgbp, generation, 0, nullptr);
+ mOutputBufferQueue->configure(nullIgbp, generation, 0, maxDequeueCount, nullptr);
} else {
- mOutputBufferQueue->configure(surface, generation, bqId, nullptr);
+ mOutputBufferQueue->configure(surface, generation, bqId, maxDequeueCount, mBase1_2 ?
+ &syncObj : nullptr);
}
ALOGD("surface generation remote change %u HAL ver: %s",
generation, syncObj ? "1.2" : "1.0");
diff --git a/media/codec2/hidl/client/include/codec2/hidl/client.h b/media/codec2/hidl/client/include/codec2/hidl/client.h
index eca268e..347e58a 100644
--- a/media/codec2/hidl/client/include/codec2/hidl/client.h
+++ b/media/codec2/hidl/client/include/codec2/hidl/client.h
@@ -384,7 +384,8 @@
c2_status_t setOutputSurface(
C2BlockPool::local_id_t blockPoolId,
const sp<IGraphicBufferProducer>& surface,
- uint32_t generation);
+ uint32_t generation,
+ int maxDequeueBufferCount);
// Extract a slot number from of the block, then call
// IGraphicBufferProducer::queueBuffer().
diff --git a/media/codec2/hidl/client/include/codec2/hidl/output.h b/media/codec2/hidl/client/include/codec2/hidl/output.h
index 0f03b36..877148a 100644
--- a/media/codec2/hidl/client/include/codec2/hidl/output.h
+++ b/media/codec2/hidl/client/include/codec2/hidl/output.h
@@ -47,6 +47,7 @@
bool configure(const sp<IGraphicBufferProducer>& igbp,
uint32_t generation,
uint64_t bqId,
+ int maxDequeueBufferCount,
std::shared_ptr<V1_2::SurfaceSyncObj> *syncObj);
// Render a graphic block to current surface.
diff --git a/media/codec2/hidl/client/output.cpp b/media/codec2/hidl/client/output.cpp
index 7df0da2..283ed8d 100644
--- a/media/codec2/hidl/client/output.cpp
+++ b/media/codec2/hidl/client/output.cpp
@@ -178,6 +178,7 @@
bool OutputBufferQueue::configure(const sp<IGraphicBufferProducer>& igbp,
uint32_t generation,
uint64_t bqId,
+ int maxDequeueBufferCount,
std::shared_ptr<V1_2::SurfaceSyncObj> *syncObj) {
uint64_t consumerUsage = 0;
if (igbp->getConsumerUsage(&consumerUsage) != OK) {
@@ -219,6 +220,20 @@
{
std::scoped_lock<std::mutex> l(mMutex);
if (generation == mGeneration) {
+ // case of old BlockPool destruction
+ C2SyncVariables *var = mSyncMem ? mSyncMem->mem() : nullptr;
+ if (var) {
+ *syncObj = std::make_shared<V1_2::SurfaceSyncObj>();
+ (*syncObj)->bqId = bqId;
+ (*syncObj)->syncMemory = mSyncMem->handle();
+ (*syncObj)->generationId = generation;
+ (*syncObj)->consumerUsage = consumerUsage;
+ mMaxDequeueBufferCount = maxDequeueBufferCount;
+ var->lock();
+ var->setSyncStatusLocked(C2SyncVariables::STATUS_INIT);
+ var->setInitialDequeueCountLocked(mMaxDequeueBufferCount, 0);
+ var->unlock();
+ }
return false;
}
std::shared_ptr<C2SurfaceSyncMemory> oldMem = mSyncMem;
@@ -238,6 +253,7 @@
mGeneration = generation;
mBqId = bqId;
mOwner = std::make_shared<int>(0);
+ mMaxDequeueBufferCount = maxDequeueBufferCount;
for (int i = 0; i < BufferQueueDefs::NUM_BUFFER_SLOTS; ++i) {
if (mBqId == 0 || !mBuffers[i]) {
continue;
@@ -288,7 +304,9 @@
mPoolDatas[i] = poolDatas[i];
}
if (newSync) {
- newSync->setInitialDequeueCount(mMaxDequeueBufferCount, success);
+ newSync->lock();
+ newSync->setInitialDequeueCountLocked(mMaxDequeueBufferCount, success);
+ newSync->unlock();
}
}
ALOGD("remote graphic buffer migration %zu/%zu",
@@ -452,6 +470,7 @@
syncVar->unlock();
}
mMutex.unlock();
+ ALOGD("set max dequeue count %d from update", maxDequeueBufferCount);
}
} // namespace c2
diff --git a/media/codec2/hidl/plugin/FilterWrapperStub.cpp b/media/codec2/hidl/plugin/FilterWrapperStub.cpp
index 1b94a1a..01ca596 100644
--- a/media/codec2/hidl/plugin/FilterWrapperStub.cpp
+++ b/media/codec2/hidl/plugin/FilterWrapperStub.cpp
@@ -42,10 +42,10 @@
}
c2_status_t FilterWrapper::createBlockPool(
- C2PlatformAllocatorStore::id_t,
- std::shared_ptr<const C2Component>,
- std::shared_ptr<C2BlockPool> *) {
- return C2_OMITTED;
+ C2PlatformAllocatorStore::id_t allocatorId,
+ std::shared_ptr<const C2Component> component,
+ std::shared_ptr<C2BlockPool> *pool) {
+ return CreateCodec2BlockPool(allocatorId, component, pool);
}
} // namespace android
diff --git a/media/codec2/hidl/services/seccomp_policy/android.hardware.media.c2@1.2-default-arm64.policy b/media/codec2/hidl/services/seccomp_policy/android.hardware.media.c2@1.2-default-arm64.policy
index f701987..5d0284f 100644
--- a/media/codec2/hidl/services/seccomp_policy/android.hardware.media.c2@1.2-default-arm64.policy
+++ b/media/codec2/hidl/services/seccomp_policy/android.hardware.media.c2@1.2-default-arm64.policy
@@ -35,7 +35,7 @@
# on ARM is statically loaded at 0xffff 0000. See
# http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0211h/Babfeega.html
# for more details.
-mremap: arg3 == 3
+mremap: arg3 == 3 || arg3 == MREMAP_MAYMOVE
munmap: 1
prctl: 1
writev: 1
diff --git a/media/codec2/sfplugin/C2OMXNode.cpp b/media/codec2/sfplugin/C2OMXNode.cpp
index f66dc11..c049187 100644
--- a/media/codec2/sfplugin/C2OMXNode.cpp
+++ b/media/codec2/sfplugin/C2OMXNode.cpp
@@ -90,6 +90,10 @@
}
}
+ void setPriority(int priority) {
+ androidSetThreadPriority(getTid(), priority);
+ }
+
protected:
bool threadLoop() override {
constexpr nsecs_t kIntervalNs = nsecs_t(10) * 1000 * 1000; // 10ms
@@ -529,4 +533,8 @@
return *mDataspace.lock();
}
+void C2OMXNode::setPriority(int priority) {
+ mQueueThread->setPriority(priority);
+}
+
} // namespace android
diff --git a/media/codec2/sfplugin/C2OMXNode.h b/media/codec2/sfplugin/C2OMXNode.h
index 9c04969..6669318 100644
--- a/media/codec2/sfplugin/C2OMXNode.h
+++ b/media/codec2/sfplugin/C2OMXNode.h
@@ -98,6 +98,11 @@
*/
android_dataspace getDataspace();
+ /**
+ * Sets priority of the queue thread.
+ */
+ void setPriority(int priority);
+
private:
std::weak_ptr<Codec2Client::Component> mComp;
sp<IOMXBufferSource> mBufferSource;
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index bae82f6..0a895b0 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -397,6 +397,14 @@
// consumer usage is queried earlier.
+ // priority
+ if (mConfig.mPriority != config.mPriority) {
+ if (config.mPriority != INT_MAX) {
+ mNode->setPriority(config.mPriority);
+ }
+ mConfig.mPriority = config.mPriority;
+ }
+
if (status.str().empty()) {
ALOGD("ISConfig not changed");
} else {
@@ -944,6 +952,7 @@
}
}
config->mISConfig->mUsage = 0;
+ config->mISConfig->mPriority = INT_MAX;
}
/*
@@ -1135,6 +1144,16 @@
configUpdate.push_back(std::move(qp));
}
+ int32_t background = 0;
+ if ((config->mDomain & Config::IS_VIDEO)
+ && msg->findInt32("android._background-mode", &background)
+ && background) {
+ androidSetThreadPriority(gettid(), ANDROID_PRIORITY_BACKGROUND);
+ if (config->mISConfig) {
+ config->mISConfig->mPriority = ANDROID_PRIORITY_BACKGROUND;
+ }
+ }
+
err = config->setParameters(comp, configUpdate, C2_DONT_BLOCK);
if (err != OK) {
ALOGW("failed to configure c2 params");
@@ -2151,7 +2170,7 @@
}
// handle configuration changes in work done
- const C2StreamInitDataInfo::output *initData = nullptr;
+ std::unique_ptr<C2Param> initData;
sp<AMessage> outputFormat = nullptr;
{
Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
@@ -2229,10 +2248,14 @@
if (config->mInputSurface) {
config->mInputSurface->onInputBufferDone(work->input.ordinal.frameIndex);
}
- initData = initDataWatcher.hasChanged() ? initDataWatcher.update().get() : nullptr;
+ if (initDataWatcher.hasChanged()) {
+ initData = C2Param::Copy(*initDataWatcher.update().get());
+ }
outputFormat = config->mOutputFormat;
}
- mChannel->onWorkDone(std::move(work), outputFormat, initData);
+ mChannel->onWorkDone(
+ std::move(work), outputFormat,
+ initData ? (C2StreamInitDataInfo::output *)initData.get() : nullptr);
break;
}
case kWhatWatch: {
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index d0c1357..e33a5ba 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -1189,9 +1189,6 @@
}
outputGeneration = output->generation;
}
- if (maxDequeueCount > 0) {
- mComponent->setOutputSurfaceMaxDequeueCount(maxDequeueCount);
- }
bool graphic = (oStreamFormat.value == C2BufferData::GRAPHIC);
C2BlockPool::local_id_t outputPoolId_;
@@ -1331,7 +1328,8 @@
mComponent->setOutputSurface(
outputPoolId_,
outputSurface,
- outputGeneration);
+ outputGeneration,
+ maxDequeueCount);
}
if (oStreamFormat.value == C2BufferData::LINEAR) {
@@ -1947,10 +1945,11 @@
& ((1 << 10) - 1));
sp<IGraphicBufferProducer> producer;
+ int maxDequeueCount = mOutputSurface.lock()->maxDequeueBuffers;
if (newSurface) {
newSurface->setScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
newSurface->setDequeueTimeout(kDequeueTimeoutNs);
- newSurface->setMaxDequeuedBufferCount(mOutputSurface.lock()->maxDequeueBuffers);
+ newSurface->setMaxDequeuedBufferCount(maxDequeueCount);
producer = newSurface->getIGraphicBufferProducer();
producer->setGenerationNumber(generation);
} else {
@@ -1970,7 +1969,8 @@
if (mComponent->setOutputSurface(
outputPoolId,
producer,
- generation) != C2_OK) {
+ generation,
+ maxDequeueCount) != C2_OK) {
ALOGI("[%s] setSurface: component setOutputSurface failed", mName);
return INVALID_OPERATION;
}
diff --git a/media/codec2/sfplugin/InputSurfaceWrapper.h b/media/codec2/sfplugin/InputSurfaceWrapper.h
index 50d600c..44ba78a 100644
--- a/media/codec2/sfplugin/InputSurfaceWrapper.h
+++ b/media/codec2/sfplugin/InputSurfaceWrapper.h
@@ -79,6 +79,7 @@
float mFixedAdjustedFps = 0.0; // fixed fps via PTS manipulation
float mMinAdjustedFps = 0.0; // minimum fps via PTS manipulation
uint64_t mUsage = 0; // consumer usage
+ int mPriority = INT_MAX; // priority of queue thread (if any); INT_MAX for no-op
};
/**
diff --git a/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp b/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp
index a78d811..0966988 100644
--- a/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp
+++ b/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp
@@ -346,7 +346,7 @@
}
return (img->mPlane[1].mColInc == 2
&& img->mPlane[2].mColInc == 2
- && (img->mPlane[2].mOffset - img->mPlane[1].mOffset == 1));
+ && (img->mPlane[2].mOffset == img->mPlane[1].mOffset + 1));
}
bool IsNV21(const MediaImage2 *img) {
@@ -355,7 +355,7 @@
}
return (img->mPlane[1].mColInc == 2
&& img->mPlane[2].mColInc == 2
- && (img->mPlane[1].mOffset - img->mPlane[2].mOffset == 1));
+ && (img->mPlane[1].mOffset == img->mPlane[2].mOffset + 1));
}
bool IsI420(const MediaImage2 *img) {
diff --git a/media/codec2/sfplugin/utils/Codec2Mapper.cpp b/media/codec2/sfplugin/utils/Codec2Mapper.cpp
index 1390642..00bf84f 100644
--- a/media/codec2/sfplugin/utils/Codec2Mapper.cpp
+++ b/media/codec2/sfplugin/utils/Codec2Mapper.cpp
@@ -311,6 +311,8 @@
{ C2Config::PCM_8, kAudioEncodingPcm8bit },
{ C2Config::PCM_16, kAudioEncodingPcm16bit },
{ C2Config::PCM_FLOAT, kAudioEncodingPcmFloat },
+ { C2Config::PCM_24, kAudioEncodingPcm24bitPacked },
+ { C2Config::PCM_32, kAudioEncodingPcm32bit },
};
ALookup<C2Config::level_t, int32_t> sVp9Levels = {
diff --git a/media/codec2/vndk/include/C2SurfaceSyncObj.h b/media/codec2/vndk/include/C2SurfaceSyncObj.h
index 16e9a9d..ac87fe4 100644
--- a/media/codec2/vndk/include/C2SurfaceSyncObj.h
+++ b/media/codec2/vndk/include/C2SurfaceSyncObj.h
@@ -53,7 +53,7 @@
* \param maxDequeueCount Initial value of # of max dequeued buffer count
* \param curDequeueCount Initial value of # of current dequeued buffer count
*/
- void setInitialDequeueCount(int32_t maxDequeueCount, int32_t curDequeueCount);
+ void setInitialDequeueCountLocked(int32_t maxDequeueCount, int32_t curDequeueCount);
/**
* Get a waitId which will be used to implement fence.
diff --git a/media/codec2/vndk/platform/C2BqBuffer.cpp b/media/codec2/vndk/platform/C2BqBuffer.cpp
index 2944925..169de0c 100644
--- a/media/codec2/vndk/platform/C2BqBuffer.cpp
+++ b/media/codec2/vndk/platform/C2BqBuffer.cpp
@@ -316,12 +316,15 @@
}
return C2_BLOCKING;
}
+ syncVar->notifyDequeuedLocked();
+ syncVar->unlock();
c2Status = dequeueBuffer(width, height, format, androidUsage,
&slot, &bufferNeedsReallocation, &fence);
- if (c2Status == C2_OK) {
- syncVar->notifyDequeuedLocked();
+ if (c2Status != C2_OK) {
+ syncVar->lock();
+ syncVar->notifyQueuedLocked();
+ syncVar->unlock();
}
- syncVar->unlock();
} else {
c2Status = dequeueBuffer(width, height, format, usage,
&slot, &bufferNeedsReallocation, &fence);
@@ -789,7 +792,7 @@
sp<GraphicBuffer> newBuffer = new GraphicBuffer(
graphicBuffer->handle, GraphicBuffer::CLONE_HANDLE,
graphicBuffer->width, graphicBuffer->height, graphicBuffer->format,
- graphicBuffer->layerCount, toUsage, graphicBuffer->stride);
+ graphicBuffer->layerCount, toUsage | graphicBuffer->getUsage(), graphicBuffer->stride);
if (newBuffer->initCheck() == android::NO_ERROR) {
graphicBuffer = std::move(newBuffer);
} else {
diff --git a/media/codec2/vndk/platform/C2SurfaceSyncObj.cpp b/media/codec2/vndk/platform/C2SurfaceSyncObj.cpp
index 587992e..e55bdc0 100644
--- a/media/codec2/vndk/platform/C2SurfaceSyncObj.cpp
+++ b/media/codec2/vndk/platform/C2SurfaceSyncObj.cpp
@@ -157,12 +157,10 @@
return 0;
}
-void C2SyncVariables::setInitialDequeueCount(
+void C2SyncVariables::setInitialDequeueCountLocked(
int32_t maxDequeueCount, int32_t curDequeueCount) {
- lock();
mMaxDequeueCount = maxDequeueCount;
mCurDequeueCount = curDequeueCount;
- unlock();
}
uint32_t C2SyncVariables::getWaitIdLocked() {
diff --git a/media/codecs/m4v_h263/dec/test/Android.bp b/media/codecs/m4v_h263/dec/test/Android.bp
index 9459ed1..6eed66f 100644
--- a/media/codecs/m4v_h263/dec/test/Android.bp
+++ b/media/codecs/m4v_h263/dec/test/Android.bp
@@ -28,7 +28,24 @@
cc_test {
name: "Mpeg4H263DecoderTest",
gtest: true,
- test_suites: ["device-tests"],
+
+ test_suites: [
+ "device-tests",
+ "mts",
+ ],
+
+ // Support multilib variants (using different suffix per sub-architecture), which is needed on
+ // build targets with secondary architectures, as the MTS test suite packaging logic flattens
+ // all test artifacts into a single `testcases` directory.
+ compile_multilib: "both",
+ multilib: {
+ lib32: {
+ suffix: "32",
+ },
+ lib64: {
+ suffix: "64",
+ },
+ },
srcs: [
"Mpeg4H263DecoderTest.cpp",
diff --git a/media/codecs/m4v_h263/dec/test/AndroidTest.xml b/media/codecs/m4v_h263/dec/test/AndroidTest.xml
index f572b0c..8bb4d1c 100755
--- a/media/codecs/m4v_h263/dec/test/AndroidTest.xml
+++ b/media/codecs/m4v_h263/dec/test/AndroidTest.xml
@@ -15,9 +15,10 @@
-->
<configuration description="Test module config for Mpeg4H263 Decoder unit tests">
<option name="test-suite-tag" value="Mpeg4H263DecoderTest" />
- <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
<option name="cleanup" value="true" />
<option name="push" value="Mpeg4H263DecoderTest->/data/local/tmp/Mpeg4H263DecoderTest" />
+ <option name="append-bitness" value="true" />
<option name="push-file"
key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/codecs/m4v_h263/dec/test/Mpeg4H263Decoder-1.1.zip?unzip=true"
value="/data/local/tmp/Mpeg4H263DecoderTestRes/" />
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index b1d72e8..416884e 100644
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -62,6 +62,16 @@
#define ALAC_SPECIFIC_INFO_SIZE (36)
+// TODO : Remove the defines once mainline media is built against NDK >= 31.
+// The mp4 extractor is part of mainline and builds against NDK 29 as of
+// writing. These keys are available only from NDK 31:
+#define AMEDIAFORMAT_KEY_MPEGH_PROFILE_LEVEL_INDICATION \
+ "mpegh-profile-level-indication"
+#define AMEDIAFORMAT_KEY_MPEGH_REFERENCE_CHANNEL_LAYOUT \
+ "mpegh-reference-channel-layout"
+#define AMEDIAFORMAT_KEY_MPEGH_COMPATIBLE_SETS \
+ "mpegh-compatible-sets"
+
namespace android {
enum {
@@ -139,6 +149,7 @@
bool mIsHEVC;
bool mIsDolbyVision;
bool mIsAC4;
+ bool mIsMpegH = false;
bool mIsPcm;
size_t mNALLengthSize;
@@ -378,6 +389,10 @@
case FOURCC(".mp3"):
case 0x6D730055: // "ms U" mp3 audio
return MEDIA_MIMETYPE_AUDIO_MPEG;
+ case FOURCC("mha1"):
+ return MEDIA_MIMETYPE_AUDIO_MPEGH_MHA1;
+ case FOURCC("mhm1"):
+ return MEDIA_MIMETYPE_AUDIO_MPEGH_MHM1;
default:
ALOGW("Unknown fourcc: %c%c%c%c",
(fourcc >> 24) & 0xff,
@@ -1778,6 +1793,8 @@
case FOURCC("fLaC"):
case FOURCC(".mp3"):
case 0x6D730055: // "ms U" mp3 audio
+ case FOURCC("mha1"):
+ case FOURCC("mhm1"):
{
if (mIsQT && depth >= 1 && mPath[depth - 1] == FOURCC("wave")) {
@@ -1977,7 +1994,94 @@
}
break;
}
+ case FOURCC("mhaC"):
+ {
+ // See ISO_IEC_23008-3;2019 MHADecoderConfigurationRecord
+ constexpr uint32_t mhac_header_size = 4 /* size */ + 4 /* boxtype 'mhaC' */
+ + 1 /* configurationVersion */ + 1 /* mpegh3daProfileLevelIndication */
+ + 1 /* referenceChannelLayout */ + 2 /* mpegh3daConfigLength */;
+ uint8_t mhac_header[mhac_header_size];
+ off64_t data_offset = *offset;
+ if (chunk_size < sizeof(mhac_header)) {
+ return ERROR_MALFORMED;
+ }
+
+ if (mDataSource->readAt(data_offset, mhac_header, sizeof(mhac_header))
+ < (ssize_t)sizeof(mhac_header)) {
+ return ERROR_IO;
+ }
+
+ //get mpegh3daProfileLevelIndication
+ const uint32_t mpegh3daProfileLevelIndication = mhac_header[9];
+ AMediaFormat_setInt32(mLastTrack->meta,
+ AMEDIAFORMAT_KEY_MPEGH_PROFILE_LEVEL_INDICATION,
+ mpegh3daProfileLevelIndication);
+
+ //get referenceChannelLayout
+ const uint32_t referenceChannelLayout = mhac_header[10];
+ AMediaFormat_setInt32(mLastTrack->meta,
+ AMEDIAFORMAT_KEY_MPEGH_REFERENCE_CHANNEL_LAYOUT,
+ referenceChannelLayout);
+
+ // get mpegh3daConfigLength
+ const uint32_t mhac_config_size = U16_AT(&mhac_header[11]);
+ if (chunk_size != sizeof(mhac_header) + mhac_config_size) {
+ return ERROR_MALFORMED;
+ }
+
+ data_offset += sizeof(mhac_header);
+ uint8_t mhac_config[mhac_config_size];
+ if (mDataSource->readAt(data_offset, mhac_config, sizeof(mhac_config))
+ < (ssize_t)sizeof(mhac_config)) {
+ return ERROR_IO;
+ }
+
+ AMediaFormat_setBuffer(mLastTrack->meta,
+ AMEDIAFORMAT_KEY_CSD_0, mhac_config, sizeof(mhac_config));
+ data_offset += sizeof(mhac_config);
+ *offset = data_offset;
+ break;
+ }
+ case FOURCC("mhaP"):
+ {
+ // FDAmd_2 of ISO_IEC_23008-3;2019 MHAProfileAndLevelCompatibilitySetBox
+ constexpr uint32_t mhap_header_size = 4 /* size */ + 4 /* boxtype 'mhaP' */
+ + 1 /* numCompatibleSets */;
+
+ uint8_t mhap_header[mhap_header_size];
+ off64_t data_offset = *offset;
+
+ if (chunk_size < (ssize_t)mhap_header_size) {
+ return ERROR_MALFORMED;
+ }
+
+ if (mDataSource->readAt(data_offset, mhap_header, sizeof(mhap_header))
+ < (ssize_t)sizeof(mhap_header)) {
+ return ERROR_IO;
+ }
+
+ // mhap_compatible_sets_size = numCompatibleSets * sizeof(uint8_t)
+ const uint32_t mhap_compatible_sets_size = mhap_header[8];
+ if (chunk_size != sizeof(mhap_header) + mhap_compatible_sets_size) {
+ return ERROR_MALFORMED;
+ }
+
+ data_offset += sizeof(mhap_header);
+ uint8_t mhap_compatible_sets[mhap_compatible_sets_size];
+ if (mDataSource->readAt(
+ data_offset, mhap_compatible_sets, sizeof(mhap_compatible_sets))
+ < (ssize_t)sizeof(mhap_compatible_sets)) {
+ return ERROR_IO;
+ }
+
+ AMediaFormat_setBuffer(mLastTrack->meta,
+ AMEDIAFORMAT_KEY_MPEGH_COMPATIBLE_SETS,
+ mhap_compatible_sets, sizeof(mhap_compatible_sets));
+ data_offset += sizeof(mhap_compatible_sets);
+ *offset = data_offset;
+ break;
+ }
case FOURCC("mp4v"):
case FOURCC("encv"):
case FOURCC("s263"):
@@ -5001,6 +5105,8 @@
bool success = AMediaFormat_getString(mFormat, AMEDIAFORMAT_KEY_MIME, &mime);
CHECK(success);
+ mIsMpegH = !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEGH_MHA1) ||
+ !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEGH_MHM1);
mIsAVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
mIsHEVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC) ||
!strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC);
@@ -6072,10 +6178,11 @@
}
uint32_t syncSampleIndex = sampleIndex;
- // assume every non-USAC audio sample is a sync sample. This works around
+ // assume every non-USAC/non-MPEGH audio sample is a sync sample.
+ // This works around
// seek issues with files that were incorrectly written with an
// empty or single-sample stss block for the audio track
- if (err == OK && (!mIsAudio || mIsUsac)) {
+ if (err == OK && (!mIsAudio || mIsUsac || mIsMpegH)) {
err = mSampleTable->findSyncSampleNear(
sampleIndex, &syncSampleIndex, findFlags);
}
diff --git a/media/extractors/wav/WAVExtractor.cpp b/media/extractors/wav/WAVExtractor.cpp
index 901b29d..9e94587 100644
--- a/media/extractors/wav/WAVExtractor.cpp
+++ b/media/extractors/wav/WAVExtractor.cpp
@@ -440,19 +440,22 @@
int64_t seekTimeUs;
ReadOptions::SeekMode mode;
if (options != NULL && options->getSeekTo(&seekTimeUs, &mode)) {
- int64_t pos = 0;
-
+ int64_t pos;
+ int64_t sampleNumber;
+ bool overflowed = __builtin_mul_overflow(seekTimeUs, mSampleRate, &sampleNumber);
+ sampleNumber /= 1000000;
if (mWaveFormat == WAVE_FORMAT_MSGSM) {
// 65 bytes decode to 320 8kHz samples
- int64_t samplenumber = (seekTimeUs * mSampleRate) / 1000000;
- int64_t framenumber = samplenumber / 320;
- pos = framenumber * 65;
+ pos = sampleNumber / 320 * 65;
} else {
- pos = (seekTimeUs * mSampleRate) / 1000000 * mNumChannels * (mBitsPerSample >> 3);
+ int64_t bytesPerFrame;
+ overflowed |= __builtin_mul_overflow(mNumChannels, mBitsPerSample >> 3, &bytesPerFrame);
+ overflowed |= __builtin_mul_overflow(bytesPerFrame, sampleNumber, &pos);
}
- if (pos > (off64_t)mSize) {
- pos = mSize;
+ if (overflowed) {
+ return AMEDIA_ERROR_MALFORMED;
}
+ pos = std::clamp(pos, (int64_t) 0, (int64_t) mSize);
mCurrentPos = pos + mOffset;
}
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index d7d7642..de8fe6a 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -314,11 +314,19 @@
}
void AudioStreamRecord::close_l() {
+ // The callbacks are normally joined in the AudioRecord destructor.
+ // But if another object has a reference to the AudioRecord then
+ // it will not get deleted here.
+ // So we should join callbacks explicitly before returning.
+ // Unlock around the join to avoid deadlocks if the callback tries to lock.
+ // This can happen if the callback returns AAUDIO_CALLBACK_RESULT_STOP
+ mStreamLock.unlock();
+ mAudioRecord->stopAndJoinCallbacks();
+ mStreamLock.lock();
+
mAudioRecord.clear();
- // Do not close mFixedBlockWriter because a data callback
- // thread might still be running if someone else has a reference
- // to mAudioRecord.
- // It has a unique_ptr to its buffer so it will clean up by itself.
+ // Do not close mFixedBlockReader. It has a unique_ptr to its buffer
+ // so it will clean up by itself.
AudioStream::close_l();
}
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index f5df07e..2ee5cdc 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -265,12 +265,18 @@
}
void AudioStreamTrack::close_l() {
- // Stop callbacks before deleting mFixedBlockReader memory.
+ // The callbacks are normally joined in the AudioTrack destructor.
+ // But if another object has a reference to the AudioTrack then
+ // it will not get deleted here.
+ // So we should join callbacks explicitly before returning.
+ // Unlock around the join to avoid deadlocks if the callback tries to lock.
+ // This can happen if the callback returns AAUDIO_CALLBACK_RESULT_STOP
+ mStreamLock.unlock();
+ mAudioTrack->stopAndJoinCallbacks();
+ mStreamLock.lock();
mAudioTrack.clear();
- // Do not close mFixedBlockReader because a data callback
- // thread might still be running if someone else has a reference
- // to mAudioRecord.
- // It has a unique_ptr to its buffer so it will clean up by itself.
+ // Do not close mFixedBlockReader. It has a unique_ptr to its buffer
+ // so it will clean up by itself.
AudioStream::close_l();
}
diff --git a/media/libaaudio/tests/Android.bp b/media/libaaudio/tests/Android.bp
index f9eebd7..98e9727 100644
--- a/media/libaaudio/tests/Android.bp
+++ b/media/libaaudio/tests/Android.bp
@@ -209,9 +209,9 @@
}
cc_test {
- name: "test_stop_hang",
+ name: "test_callback_race",
defaults: ["libaaudio_tests_defaults"],
- srcs: ["test_stop_hang.cpp"],
+ srcs: ["test_callback_race.cpp"],
shared_libs: [
"libaaudio",
"libbinder",
diff --git a/media/libaaudio/tests/test_callback_race.cpp b/media/libaaudio/tests/test_callback_race.cpp
new file mode 100644
index 0000000..843d5d7
--- /dev/null
+++ b/media/libaaudio/tests/test_callback_race.cpp
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Test whether the callback is joined before the close finishes.
+ *
+ * Start a stream with a callback.
+ * The callback just sleeps for a long time.
+ * While the callback is sleeping, close() the stream from the main thread.
+ * Then check to make sure the callback was joined before the close() returns.
+ *
+ * This can hang if there are deadlocks. So make sure you get a PASSED result.
+ */
+
+#include <atomic>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <gtest/gtest.h>
+
+#include <aaudio/AAudio.h>
+
+// Sleep long enough that the foreground has a change to call close.
+static constexpr int kCallbackSleepMicros = 600 * 1000;
+
+class AudioEngine {
+public:
+
+ // Check for a crash or late callback if we close without stopping.
+ void checkCloseJoins(aaudio_direction_t direction,
+ aaudio_performance_mode_t perfMode,
+ aaudio_data_callback_result_t callbackResult) {
+
+ // Make printf print immediately so that debug info is not stuck
+ // in a buffer if we hang or crash.
+ setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
+
+ mCallbackResult = callbackResult;
+ startStreamForStall(direction, perfMode);
+ // When the callback starts it will go to sleep.
+ waitForCallbackToStart();
+
+ printf("call AAudioStream_close()\n");
+ ASSERT_FALSE(mCallbackFinished); // Still sleeping?
+ aaudio_result_t result = AAudioStream_close(mStream); // May hang here!
+ ASSERT_TRUE(mCallbackFinished);
+ ASSERT_EQ(AAUDIO_OK, result);
+ printf("AAudioStream_close() returned %d\n", result);
+
+ ASSERT_EQ(AAUDIO_OK, mError.load());
+ // Did calling stop() from callback fail? It should have.
+ ASSERT_NE(AAUDIO_OK, mStopResult.load());
+ }
+
+private:
+ void startStreamForStall(aaudio_direction_t direction,
+ aaudio_performance_mode_t perfMode) {
+ AAudioStreamBuilder* builder = nullptr;
+ aaudio_result_t result = AAUDIO_OK;
+
+ // Use an AAudioStreamBuilder to contain requested parameters.
+ result = AAudio_createStreamBuilder(&builder);
+ ASSERT_EQ(AAUDIO_OK, result);
+
+ // Request stream properties.
+ AAudioStreamBuilder_setDirection(builder, direction);
+ AAudioStreamBuilder_setPerformanceMode(builder, perfMode);
+ AAudioStreamBuilder_setDataCallback(builder, s_myDataCallbackProc, this);
+ AAudioStreamBuilder_setErrorCallback(builder, s_myErrorCallbackProc, this);
+
+ // Create an AAudioStream using the Builder.
+ result = AAudioStreamBuilder_openStream(builder, &mStream);
+ AAudioStreamBuilder_delete(builder);
+ ASSERT_EQ(AAUDIO_OK, result);
+
+ // Check to see what kind of stream we actually got.
+ int32_t deviceId = AAudioStream_getDeviceId(mStream);
+ aaudio_performance_mode_t
+ actualPerfMode = AAudioStream_getPerformanceMode(mStream);
+ printf("-------- opened: deviceId = %3d, perfMode = %d\n",
+ deviceId,
+ actualPerfMode);
+
+ // Start stream.
+ result = AAudioStream_requestStart(mStream);
+ ASSERT_EQ(AAUDIO_OK, result);
+ }
+
+ void waitForCallbackToStart() {
+ // Wait for callback to say it has been called.
+ int countDownMillis = 2000;
+ constexpr int countDownPeriodMillis = 50;
+ while (!mCallbackStarted && countDownMillis > 0) {
+ printf("Waiting for callback to start, %d\n", countDownMillis);
+ usleep(countDownPeriodMillis * 1000);
+ countDownMillis -= countDownPeriodMillis;
+ }
+ ASSERT_LT(0, countDownMillis);
+ ASSERT_TRUE(mCallbackStarted);
+ }
+
+// Callback function that fills the audio output buffer.
+ static aaudio_data_callback_result_t s_myDataCallbackProc(
+ AAudioStream *stream,
+ void *userData,
+ void * /*audioData */,
+ int32_t /* numFrames */
+ ) {
+ AudioEngine* engine = (AudioEngine*) userData;
+ engine->mCallbackStarted = true;
+ usleep(kCallbackSleepMicros);
+ // it is illegal to call stop() from the callback. It should
+ // return an error and not hang.
+ engine->mStopResult = AAudioStream_requestStop(stream);
+ engine->mCallbackFinished = true;
+ return engine->mCallbackResult;
+ }
+
+ static void s_myErrorCallbackProc(
+ AAudioStream * /* stream */,
+ void *userData,
+ aaudio_result_t error) {
+ AudioEngine *engine = (AudioEngine *)userData;
+ engine->mError = error;
+ }
+
+ AAudioStream* mStream = nullptr;
+
+ std::atomic<aaudio_result_t> mError{AAUDIO_OK}; // written by error callback
+ std::atomic<bool> mCallbackStarted{false}; // written by data callback
+ std::atomic<bool> mCallbackFinished{false}; // written by data callback
+ std::atomic<aaudio_data_callback_result_t> mCallbackResult{AAUDIO_CALLBACK_RESULT_CONTINUE};
+ std::atomic<aaudio_result_t> mStopResult{AAUDIO_OK};
+};
+
+/*********************************************************************/
+// Tell the callback to return AAUDIO_CALLBACK_RESULT_CONTINUE.
+
+TEST(test_close_timing, aaudio_close_joins_input_none) {
+ AudioEngine engine;
+ engine.checkCloseJoins(AAUDIO_DIRECTION_INPUT,
+ AAUDIO_PERFORMANCE_MODE_NONE,
+ AAUDIO_CALLBACK_RESULT_CONTINUE);
+}
+
+TEST(test_close_timing, aaudio_close_joins_output_none) {
+ AudioEngine engine;
+ engine.checkCloseJoins(AAUDIO_DIRECTION_OUTPUT,
+ AAUDIO_PERFORMANCE_MODE_NONE,
+ AAUDIO_CALLBACK_RESULT_CONTINUE);
+}
+
+TEST(test_close_timing, aaudio_close_joins_input_lowlat) {
+ AudioEngine engine;
+ engine.checkCloseJoins(AAUDIO_DIRECTION_INPUT,
+ AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
+ AAUDIO_CALLBACK_RESULT_CONTINUE);
+}
+
+TEST(test_close_timing, aaudio_close_joins_output_lowlat) {
+ AudioEngine engine;
+ engine.checkCloseJoins(AAUDIO_DIRECTION_OUTPUT,
+ AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
+ AAUDIO_CALLBACK_RESULT_CONTINUE);
+}
+
+/*********************************************************************/
+// Tell the callback to return AAUDIO_CALLBACK_RESULT_STOP.
+
+TEST(test_close_timing, aaudio_close_joins_input_lowlat_stop) {
+ AudioEngine engine;
+ engine.checkCloseJoins(AAUDIO_DIRECTION_INPUT,
+ AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
+ AAUDIO_CALLBACK_RESULT_STOP);
+}
+
+TEST(test_close_timing, aaudio_close_joins_output_lowlat_stop) {
+ AudioEngine engine;
+ engine.checkCloseJoins(AAUDIO_DIRECTION_OUTPUT,
+ AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
+ AAUDIO_CALLBACK_RESULT_STOP);
+}
+
+TEST(test_close_timing, aaudio_close_joins_output_none_stop) {
+ AudioEngine engine;
+ engine.checkCloseJoins(AAUDIO_DIRECTION_OUTPUT,
+ AAUDIO_PERFORMANCE_MODE_NONE,
+ AAUDIO_CALLBACK_RESULT_STOP);
+}
+
+TEST(test_close_timing, aaudio_close_joins_input_none_stop) {
+ AudioEngine engine;
+ engine.checkCloseJoins(AAUDIO_DIRECTION_INPUT,
+ AAUDIO_PERFORMANCE_MODE_NONE,
+ AAUDIO_CALLBACK_RESULT_STOP);
+}
diff --git a/media/libaaudio/tests/test_stop_hang.cpp b/media/libaaudio/tests/test_stop_hang.cpp
deleted file mode 100644
index 982ff4a..0000000
--- a/media/libaaudio/tests/test_stop_hang.cpp
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * Return stop from the callback
- * and then close the stream immediately.
- */
-
-#include <atomic>
-#include <mutex>
-#include <stdio.h>
-#include <thread>
-#include <unistd.h>
-
-#include <aaudio/AAudio.h>
-
-#define DURATION_SECONDS 5
-
-struct AudioEngine {
- AAudioStreamBuilder *builder = nullptr;
- AAudioStream *stream = nullptr;
- std::thread *thread = nullptr;
-
- std::atomic<bool> started{false};
- std::mutex doneLock; // Use a mutex so we can sleep on it while join()ing.
- std::atomic<bool> done{false};
-
- aaudio_result_t join() {
- aaudio_result_t result = AAUDIO_ERROR_INVALID_STATE;
- if (stream != nullptr) {
- while (true) {
- {
- // Will block if the thread is running.
- // This mutex is used to close() immediately after the callback returns
- // and before the requestStop_l() is called.
- std::lock_guard<std::mutex> lock(doneLock);
- if (done) break;
- }
- printf("join() got mutex but stream not done!");
- usleep(10 * 1000); // sleep then check again
- }
- result = AAudioStream_close(stream);
- stream = nullptr;
- }
- return result;
- }
-};
-
-// Callback function that fills the audio output buffer.
-static aaudio_data_callback_result_t s_myDataCallbackProc(
- AAudioStream *stream,
- void *userData,
- void *audioData,
- int32_t numFrames
-) {
- (void) stream;
- (void) audioData;
- (void) numFrames;
- AudioEngine *engine = (struct AudioEngine *)userData;
- std::lock_guard<std::mutex> lock(engine->doneLock);
- engine->started = true;
- usleep(DURATION_SECONDS * 1000 * 1000); // Mimic SynthMark procedure.
- engine->done = true;
- return AAUDIO_CALLBACK_RESULT_STOP;
-}
-
-static void s_myErrorCallbackProc(
- AAudioStream *stream __unused,
- void *userData __unused,
- aaudio_result_t error) {
- printf("%s() - error = %d\n", __func__, error);
-}
-
-static aaudio_result_t s_OpenAudioStream(struct AudioEngine *engine) {
- // Use an AAudioStreamBuilder to contain requested parameters.
- aaudio_result_t result = AAudio_createStreamBuilder(&engine->builder);
- if (result != AAUDIO_OK) {
- printf("AAudio_createStreamBuilder returned %s",
- AAudio_convertResultToText(result));
- return result;
- }
-
- // Request stream properties.
- AAudioStreamBuilder_setPerformanceMode(engine->builder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
- AAudioStreamBuilder_setDataCallback(engine->builder, s_myDataCallbackProc, engine);
- AAudioStreamBuilder_setErrorCallback(engine->builder, s_myErrorCallbackProc, engine);
-
- // Create an AAudioStream using the Builder.
- result = AAudioStreamBuilder_openStream(engine->builder, &engine->stream);
- if (result != AAUDIO_OK) {
- printf("AAudioStreamBuilder_openStream returned %s",
- AAudio_convertResultToText(result));
- return result;
- }
-
- return result;
-}
-
-int main(int argc, char **argv) {
- (void) argc;
- (void) argv;
- struct AudioEngine engine;
- aaudio_result_t result = AAUDIO_OK;
- int errorCount = 0;
-
- // Make printf print immediately so that debug info is not stuck
- // in a buffer if we hang or crash.
- setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
-
- printf("Test Return Stop Hang V1.0\n");
-
- result = s_OpenAudioStream(&engine);
- if (result != AAUDIO_OK) {
- printf("s_OpenAudioStream returned %s\n",
- AAudio_convertResultToText(result));
- errorCount++;
- }
-
- // Check to see what kind of stream we actually got.
- int32_t deviceId = AAudioStream_getDeviceId(engine.stream);
- aaudio_performance_mode_t actualPerfMode = AAudioStream_getPerformanceMode(engine.stream);
- printf("-------- opened: deviceId = %3d, perfMode = %d\n", deviceId, actualPerfMode);
-
- // Start stream.
- result = AAudioStream_requestStart(engine.stream);
- printf("AAudioStream_requestStart() returned %d >>>>>>>>>>>>>>>>>>>>>>\n", result);
- if (result != AAUDIO_OK) {
- errorCount++;
- } else {
- int counter = 0;
- while (!engine.started) {
- printf("Waiting for stream to start, %d\n", counter++);
- usleep(5 * 1000);
- }
- printf("You should see more messages %d seconds after this. If not then the test failed!\n",
- DURATION_SECONDS);
- result = engine.join(); // This might hang!
- AAudioStreamBuilder_delete(engine.builder);
- engine.builder = nullptr;
- }
-
- printf("aaudio result = %d = %s\n", result, AAudio_convertResultToText(result));
- printf("test %s\n", errorCount ? "FAILED" : "PASSED");
-
- return errorCount ? EXIT_FAILURE : EXIT_SUCCESS;
-}
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index e15ef3d..1a4bde9 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -181,21 +181,9 @@
.set(AMEDIAMETRICS_PROP_STATUS, (int32_t)mStatus)
.record();
+ stopAndJoinCallbacks(); // checks mStatus
+
if (mStatus == NO_ERROR) {
- // Make sure that callback function exits in the case where
- // it is looping on buffer empty condition in obtainBuffer().
- // Otherwise the callback thread will never exit.
- stop();
- if (mAudioRecordThread != 0) {
- mProxy->interrupt();
- mAudioRecordThread->requestExit(); // see comment in AudioRecord.h
- mAudioRecordThread->requestExitAndWait();
- mAudioRecordThread.clear();
- }
- // No lock here: worst case we remove a NULL callback which will be a nop
- if (mDeviceCallback != 0 && mInput != AUDIO_IO_HANDLE_NONE) {
- AudioSystem::removeAudioDeviceCallback(this, mInput, mPortId);
- }
IInterface::asBinder(mAudioRecord)->unlinkToDeath(mDeathNotifier, this);
mAudioRecord.clear();
mCblkMemory.clear();
@@ -208,6 +196,27 @@
}
}
+void AudioRecord::stopAndJoinCallbacks() {
+ // Prevent nullptr crash if it did not open properly.
+ if (mStatus != NO_ERROR) return;
+
+ // Make sure that callback function exits in the case where
+ // it is looping on buffer empty condition in obtainBuffer().
+ // Otherwise the callback thread will never exit.
+ stop();
+ if (mAudioRecordThread != 0) {
+ mProxy->interrupt();
+ mAudioRecordThread->requestExit(); // see comment in AudioRecord.h
+ mAudioRecordThread->requestExitAndWait();
+ mAudioRecordThread.clear();
+ }
+ // No lock here: worst case we remove a NULL callback which will be a nop
+ if (mDeviceCallback != 0 && mInput != AUDIO_IO_HANDLE_NONE) {
+ // This may not stop all of these device callbacks!
+ // TODO: Add some sort of protection.
+ AudioSystem::removeAudioDeviceCallback(this, mInput, mPortId);
+ }
+}
status_t AudioRecord::set(
audio_source_t inputSource,
uint32_t sampleRate,
@@ -226,7 +235,8 @@
const audio_attributes_t* pAttributes,
audio_port_handle_t selectedDeviceId,
audio_microphone_direction_t selectedMicDirection,
- float microphoneFieldDimension)
+ float microphoneFieldDimension,
+ int32_t maxSharedAudioHistoryMs)
{
status_t status = NO_ERROR;
uint32_t channelCount;
@@ -259,6 +269,7 @@
mSelectedDeviceId = selectedDeviceId;
mSelectedMicDirection = selectedMicDirection;
mSelectedMicFieldDimension = microphoneFieldDimension;
+ mMaxSharedAudioHistoryMs = maxSharedAudioHistoryMs;
switch (transferType) {
case TRANSFER_DEFAULT:
@@ -807,6 +818,7 @@
input.selectedDeviceId = mSelectedDeviceId;
input.sessionId = mSessionId;
originalSessionId = mSessionId;
+ input.maxSharedAudioHistoryMs = mMaxSharedAudioHistoryMs;
do {
media::CreateRecordResponse response;
@@ -828,7 +840,7 @@
usleep((20 + rand() % 30) * 10000);
} while (1);
- ALOG_ASSERT(record != 0);
+ ALOG_ASSERT(output.audioRecord != 0);
// AudioFlinger now owns the reference to the I/O handle,
// so we are no longer responsible for releasing it.
@@ -916,6 +928,10 @@
AudioSystem::addAudioDeviceCallback(this, output.inputId, output.portId);
}
+ if (!mSharedAudioPackageName.empty()) {
+ mAudioRecord->shareAudioHistory(mSharedAudioPackageName, mSharedAudioStartMs);
+ }
+
mPortId = output.portId;
// We retain a copy of the I/O handle, but don't own the reference
mInput = output.inputId;
@@ -1569,7 +1585,7 @@
void AudioRecord::setLogSessionId(const char *logSessionId)
{
- AutoMutex lock(mLock);
+ AutoMutex lock(mLock);
if (logSessionId == nullptr) logSessionId = ""; // an empty string is an unset session id.
if (mLogSessionId == logSessionId) return;
@@ -1580,6 +1596,22 @@
.record();
}
+status_t AudioRecord::shareAudioHistory(const std::string& sharedPackageName,
+ int64_t sharedStartMs)
+{
+ AutoMutex lock(mLock);
+ if (mAudioRecord == 0) {
+ return NO_INIT;
+ }
+ status_t status = statusTFromBinderStatus(
+ mAudioRecord->shareAudioHistory(sharedPackageName, sharedStartMs));
+ if (status == NO_ERROR) {
+ mSharedAudioPackageName = sharedPackageName;
+ mSharedAudioStartMs = sharedStartMs;
+ }
+ return status;
+}
+
// =========================================================================
void AudioRecord::DeathNotifier::binderDied(const wp<IBinder>& who __unused)
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 6c9e85c..1bc3baa 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -327,21 +327,9 @@
.set(AMEDIAMETRICS_PROP_STATUS, (int32_t)mStatus)
.record();
+ stopAndJoinCallbacks(); // checks mStatus
+
if (mStatus == NO_ERROR) {
- // Make sure that callback function exits in the case where
- // it is looping on buffer full condition in obtainBuffer().
- // Otherwise the callback thread will never exit.
- stop();
- if (mAudioTrackThread != 0) {
- mProxy->interrupt();
- mAudioTrackThread->requestExit(); // see comment in AudioTrack.h
- mAudioTrackThread->requestExitAndWait();
- mAudioTrackThread.clear();
- }
- // No lock here: worst case we remove a NULL callback which will be a nop
- if (mDeviceCallback != 0 && mOutput != AUDIO_IO_HANDLE_NONE) {
- AudioSystem::removeAudioDeviceCallback(this, mOutput, mPortId);
- }
IInterface::asBinder(mAudioTrack)->unlinkToDeath(mDeathNotifier, this);
mAudioTrack.clear();
mCblkMemory.clear();
@@ -355,6 +343,29 @@
}
}
+void AudioTrack::stopAndJoinCallbacks() {
+ // Prevent nullptr crash if it did not open properly.
+ if (mStatus != NO_ERROR) return;
+
+ // Make sure that callback function exits in the case where
+ // it is looping on buffer full condition in obtainBuffer().
+ // Otherwise the callback thread will never exit.
+ stop();
+ if (mAudioTrackThread != 0) { // not thread safe
+ mProxy->interrupt();
+ mAudioTrackThread->requestExit(); // see comment in AudioTrack.h
+ mAudioTrackThread->requestExitAndWait();
+ mAudioTrackThread.clear();
+ }
+ // No lock here: worst case we remove a NULL callback which will be a nop
+ if (mDeviceCallback != 0 && mOutput != AUDIO_IO_HANDLE_NONE) {
+ // This may not stop all of these device callbacks!
+ // TODO: Add some sort of protection.
+ AudioSystem::removeAudioDeviceCallback(this, mOutput, mPortId);
+ mDeviceCallback.clear();
+ }
+}
+
status_t AudioTrack::set(
audio_stream_type_t streamType,
uint32_t sampleRate,
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index 0feafc5..7656307 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -138,6 +138,8 @@
aidl.config = VALUE_OR_RETURN(legacy2aidl_audio_config_base_t_AudioConfigBase(config));
aidl.clientInfo = VALUE_OR_RETURN(legacy2aidl_AudioClient_AudioClient(clientInfo));
aidl.riid = VALUE_OR_RETURN(legacy2aidl_audio_unique_id_t_int32_t(riid));
+ aidl.maxSharedAudioHistoryMs = VALUE_OR_RETURN(
+ convertIntegral<int32_t>(maxSharedAudioHistoryMs));
aidl.flags = VALUE_OR_RETURN(legacy2aidl_audio_input_flags_t_int32_t_mask(flags));
aidl.frameCount = VALUE_OR_RETURN(convertIntegral<int64_t>(frameCount));
aidl.notificationFrameCount = VALUE_OR_RETURN(convertIntegral<int64_t>(notificationFrameCount));
@@ -151,10 +153,13 @@
IAudioFlinger::CreateRecordInput::fromAidl(
const media::CreateRecordRequest& aidl) {
IAudioFlinger::CreateRecordInput legacy;
- legacy.attr = VALUE_OR_RETURN(aidl2legacy_AudioAttributesInternal_audio_attributes_t(aidl.attr));
+ legacy.attr = VALUE_OR_RETURN(
+ aidl2legacy_AudioAttributesInternal_audio_attributes_t(aidl.attr));
legacy.config = VALUE_OR_RETURN(aidl2legacy_AudioConfigBase_audio_config_base_t(aidl.config));
legacy.clientInfo = VALUE_OR_RETURN(aidl2legacy_AudioClient_AudioClient(aidl.clientInfo));
legacy.riid = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_unique_id_t(aidl.riid));
+ legacy.maxSharedAudioHistoryMs = VALUE_OR_RETURN(
+ convertIntegral<int32_t>(aidl.maxSharedAudioHistoryMs));
legacy.flags = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_input_flags_t_mask(aidl.flags));
legacy.frameCount = VALUE_OR_RETURN(convertIntegral<size_t>(aidl.frameCount));
legacy.notificationFrameCount = VALUE_OR_RETURN(
diff --git a/media/libaudioclient/aidl/android/media/CreateRecordRequest.aidl b/media/libaudioclient/aidl/android/media/CreateRecordRequest.aidl
index 62007da..5b26d22 100644
--- a/media/libaudioclient/aidl/android/media/CreateRecordRequest.aidl
+++ b/media/libaudioclient/aidl/android/media/CreateRecordRequest.aidl
@@ -34,6 +34,7 @@
AudioClient clientInfo;
/** Interpreted as audio_unique_id_t. */
int riid;
+ int maxSharedAudioHistoryMs;
/** Bitmask, indexed by AudioInputFlags. */
int flags;
long frameCount;
diff --git a/media/libaudioclient/aidl/android/media/IAudioRecord.aidl b/media/libaudioclient/aidl/android/media/IAudioRecord.aidl
index 1772653..44ef80b 100644
--- a/media/libaudioclient/aidl/android/media/IAudioRecord.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioRecord.aidl
@@ -48,4 +48,6 @@
/* Set the microphone zoom (for processing).
*/
void setPreferredMicrophoneFieldDimension(float zoom);
+
+ void shareAudioHistory(@utf8InCpp String sharedAudioPackageName, long sharedAudioStartMs);
}
diff --git a/media/libaudioclient/include/media/AudioRecord.h b/media/libaudioclient/include/media/AudioRecord.h
index 82a29d4..9965e25 100644
--- a/media/libaudioclient/include/media/AudioRecord.h
+++ b/media/libaudioclient/include/media/AudioRecord.h
@@ -241,7 +241,8 @@
audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE,
audio_microphone_direction_t
selectedMicDirection = MIC_DIRECTION_UNSPECIFIED,
- float selectedMicFieldDimension = MIC_FIELD_DIMENSION_DEFAULT);
+ float selectedMicFieldDimension = MIC_FIELD_DIMENSION_DEFAULT,
+ int32_t maxSharedAudioHistoryMs = 0);
/* Result of constructing the AudioRecord. This must be checked for successful initialization
* before using any AudioRecord API (except for set()), because using
@@ -303,6 +304,19 @@
void stop();
bool stopped() const;
+ /* Calls stop() and then wait for all of the callbacks to return.
+ * It is safe to call this if stop() or pause() has already been called.
+ *
+ * This function is called from the destructor. But since AudioRecord
+ * is ref counted, the destructor may be called later than desired.
+ * This can be called explicitly as part of closing an AudioRecord
+ * if you want to be certain that callbacks have completely finished.
+ *
+ * This is not thread safe and should only be called from one thread,
+ * ideally as the AudioRecord is being closed.
+ */
+ void stopAndJoinCallbacks();
+
/* Return the sink sample rate for this record track in Hz.
* If specified as zero in constructor or set(), this will be the source sample rate.
* Unlike AudioTrack, the sample rate is const after initialization, so doesn't need a lock.
@@ -583,6 +597,10 @@
*/
void setLogSessionId(const char *logSessionId);
+
+ status_t shareAudioHistory(const std::string& sharedPackageName,
+ int64_t sharedStartMs);
+
/*
* Dumps the state of an audio record.
*/
@@ -766,6 +784,10 @@
audio_microphone_direction_t mSelectedMicDirection;
float mSelectedMicFieldDimension;
+ int32_t mMaxSharedAudioHistoryMs = 0;
+ std::string mSharedAudioPackageName = {};
+ int64_t mSharedAudioStartMs = 0;
+
private:
class MediaMetrics {
public:
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index d167c40..c293343 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -479,6 +479,19 @@
void stop();
bool stopped() const;
+ /* Call stop() and then wait for all of the callbacks to return.
+ * It is safe to call this if stop() or pause() has already been called.
+ *
+ * This function is called from the destructor. But since AudioTrack
+ * is ref counted, the destructor may be called later than desired.
+ * This can be called explicitly as part of closing an AudioTrack
+ * if you want to be certain that callbacks have completely finished.
+ *
+ * This is not thread safe and should only be called from one thread,
+ * ideally as the AudioTrack is being closed.
+ */
+ void stopAndJoinCallbacks();
+
/* Flush a stopped or paused track. All previously buffered data is discarded immediately.
* This has the effect of draining the buffers without mixing or output.
* Flush is intended for streaming mode, for example before switching to non-contiguous content.
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index 7f7ca85..3a5d164 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -130,6 +130,7 @@
AudioClient clientInfo;
media::permission::Identity identity;
audio_unique_id_t riid;
+ int32_t maxSharedAudioHistoryMs;
/* input/output */
audio_input_flags_t flags;
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index b2056ad..e471c7b 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -45,6 +45,12 @@
enabled: false,
},
},
+ header_libs: [
+ "libbinder_headers",
+ ],
+ export_header_lib_headers: [
+ "libbinder_headers",
+ ],
apex_available: [
"//apex_available:platform",
"com.android.media",
diff --git a/media/libmediaformatshaper/Android.bp b/media/libmediaformatshaper/Android.bp
index 3107e12..bdd1465 100644
--- a/media/libmediaformatshaper/Android.bp
+++ b/media/libmediaformatshaper/Android.bp
@@ -56,6 +56,10 @@
"include",
],
+ header_libs: [
+ "libstagefright_headers",
+ ],
+
shared_libs: [
"liblog",
"libutils",
diff --git a/media/libmediaformatshaper/CodecProperties.cpp b/media/libmediaformatshaper/CodecProperties.cpp
index e6b3c46..b118af6 100644
--- a/media/libmediaformatshaper/CodecProperties.cpp
+++ b/media/libmediaformatshaper/CodecProperties.cpp
@@ -21,7 +21,9 @@
#include <string>
#include <stdlib.h>
-#include <media/formatshaper/CodecProperties.h>
+#include "CodecProperties.h"
+
+#include <media/stagefright/MediaCodecConstants.h>
// we aren't going to mess with shaping points dimensions beyond this
@@ -58,6 +60,13 @@
mTargetQpMax = qpMax;
}
+void CodecProperties::setMissingQpBoost(double boost) {
+ mMissingQpBoost = boost;
+}
+void CodecProperties::setPhaseOut(double phaseout) {
+ mPhaseOut = phaseout;
+}
+
// what API is this codec set up for (e.g. API of the associated partition)
// vendor-side (OEM) codecs may be older, due to 'vendor freeze' and treble
int CodecProperties::supportedApi() {
@@ -68,11 +77,11 @@
ALOGD("setFeatureValue(%s,%d)", key.c_str(), value);
mFeatures.insert({key, value});
- if (!strcmp(key.c_str(), "qp-bounds")) { // official key
+ if (!strcmp(key.c_str(), FEATURE_QpBounds)) {
setSupportsQp(1);
- } else if (!strcmp(key.c_str(), "vq-supports-qp")) { // key from prototyping
- setSupportsQp(1);
- } else if (!strcmp(key.c_str(), "vq-minimum-quality")) {
+ } else if (!strcmp(key.c_str(), "video-minimum-quality")) {
+ setSupportedMinimumQuality(1);
+ } else if (!strcmp(key.c_str(), "vq-minimum-quality")) { // from prototyping
setSupportedMinimumQuality(1);
}
}
@@ -132,6 +141,22 @@
setBpp(bpp);
legal = true;
}
+ } else if (!strcmp(key.c_str(), "vq-bitrate-phaseout")) {
+ const char *p = value.c_str();
+ char *q;
+ double phaseout = strtod(p, &q);
+ if (q != p) {
+ setPhaseOut(phaseout);
+ legal = true;
+ }
+ } else if (!strcmp(key.c_str(), "vq-boost-missing-qp")) {
+ const char *p = value.c_str();
+ char *q;
+ double boost = strtod(p, &q);
+ if (q != p) {
+ setMissingQpBoost(boost);
+ legal = true;
+ }
} else {
legal = true;
}
diff --git a/media/libmediaformatshaper/include/media/formatshaper/CodecProperties.h b/media/libmediaformatshaper/CodecProperties.h
similarity index 89%
rename from media/libmediaformatshaper/include/media/formatshaper/CodecProperties.h
rename to media/libmediaformatshaper/CodecProperties.h
index ff7051f..98ab99e 100644
--- a/media/libmediaformatshaper/include/media/formatshaper/CodecProperties.h
+++ b/media/libmediaformatshaper/CodecProperties.h
@@ -82,6 +82,14 @@
void setSupportsQp(bool supported) { mSupportsQp = supported;}
bool supportsQp() { return mSupportsQp;}
+ // defines our range of operation -- multiplier on the floor bitrate
+ double getPhaseOut() { return mPhaseOut; }
+ void setPhaseOut(double overageMultiplier);
+
+ // how much (0.20 = +20%) do we add if Qp is requested but unsupported
+ double getMissingQpBoost() {return mMissingQpBoost; }
+ void setMissingQpBoost(double boost);
+
int supportedApi();
// a codec is not usable until it has been registered with its
@@ -98,6 +106,11 @@
bool mSupportsQp = false;
double mBpp = 0.0;
+ // target bitrates above floor * mPhaseOut are left untouched
+ double mPhaseOut = 1.75;
+ // 20% bump if QP is configured but it is unavailable
+ double mMissingQpBoost = 0.20;
+
// allow different target bits-per-pixel based on resolution
// similar to codec 'performance points'
// uses 'next largest' (by pixel count) point as minimum bpp
diff --git a/media/libmediaformatshaper/CodecSeeding.cpp b/media/libmediaformatshaper/CodecSeeding.cpp
index a7fcc66..292b6df 100644
--- a/media/libmediaformatshaper/CodecSeeding.cpp
+++ b/media/libmediaformatshaper/CodecSeeding.cpp
@@ -20,7 +20,7 @@
#include <string>
-#include <media/formatshaper/CodecProperties.h>
+#include "CodecProperties.h"
namespace android {
namespace mediaformatshaper {
@@ -49,22 +49,28 @@
*/
static preloadTuning_t featuresAvc[] = {
- {true, "vq-target-bpp", "2.45"},
- {true, "vq-target-bpp-1080p", "2.40"},
- {true, "vq-target-bpp-540p", "2.60"},
+ {true, "vq-target-bpp-1080p", "1.90"},
+ {true, "vq-target-bpp-720p", "2.25"},
+ {true, "vq-target-bpp-540p", "2.65"},
{true, "vq-target-bpp-480p", "3.00"},
{true, "vq-target-qpmax", "40"},
+ {true, "vq-bitrate-phaseout", "1.75"},
+ {true, "vq-boost-missing-qp", "0.20"},
{true, nullptr, 0}
};
static preloadTuning_t featuresHevc[] = {
- {true, "vq-target-bpp", "2.30"},
- {true, "vq-target-qpmax", "40"}, // nop, since hevc codecs don't declare qp support
+ {true, "vq-target-bpp-1080p", "1.50"},
+ {true, "vq-target-bpp-720p", "1.80"},
+ {true, "vq-target-bpp-540p", "2.10"},
+ {true, "vq-target-qpmax", "40"},
+ {true, "vq-bitrate-phaseout", "1.75"},
+ {true, "vq-boost-missing-qp", "0.20"},
{true, nullptr, 0}
};
static preloadTuning_t featuresGenericVideo[] = {
- {true, "vq-target-bpp", "2.40"},
+ {true, "vq-target-bpp", "2.00"},
{true, nullptr, 0}
};
diff --git a/media/libmediaformatshaper/FormatShaper.cpp b/media/libmediaformatshaper/FormatShaper.cpp
index 42502e0..451f772 100644
--- a/media/libmediaformatshaper/FormatShaper.cpp
+++ b/media/libmediaformatshaper/FormatShaper.cpp
@@ -23,10 +23,11 @@
#include <media/NdkMediaFormat.h>
-#include <media/formatshaper/VQops.h>
-#include <media/formatshaper/CodecProperties.h>
+#include "CodecProperties.h"
+#include "VideoShaper.h"
+#include "VQops.h"
+
#include <media/formatshaper/FormatShaper.h>
-#include <media/formatshaper/VideoShaper.h>
namespace android {
namespace mediaformatshaper {
diff --git a/media/libmediaformatshaper/ManageShapingCodecs.cpp b/media/libmediaformatshaper/ManageShapingCodecs.cpp
index bdc395f..3061d0b 100644
--- a/media/libmediaformatshaper/ManageShapingCodecs.cpp
+++ b/media/libmediaformatshaper/ManageShapingCodecs.cpp
@@ -23,7 +23,8 @@
#include <inttypes.h>
#include <media/NdkMediaFormat.h>
-#include <media/formatshaper/CodecProperties.h>
+
+#include "CodecProperties.h"
namespace android {
namespace mediaformatshaper {
diff --git a/media/libmediaformatshaper/VQApply.cpp b/media/libmediaformatshaper/VQApply.cpp
index 08e23cc..28ce43f 100644
--- a/media/libmediaformatshaper/VQApply.cpp
+++ b/media/libmediaformatshaper/VQApply.cpp
@@ -23,9 +23,9 @@
#include <media/NdkMediaFormat.h>
-#include <media/formatshaper/VQops.h>
-#include <media/formatshaper/CodecProperties.h>
-#include <media/formatshaper/VideoShaper.h>
+#include "VQops.h"
+#include "CodecProperties.h"
+#include "VideoShaper.h"
namespace android {
namespace mediaformatshaper {
@@ -49,19 +49,12 @@
static const int BITRATE_MODE_VBR = 1;
-// constants we use within the calculations
-//
-constexpr double BITRATE_LEAVE_UNTOUCHED = 2.0;
-constexpr double BITRATE_QP_UNAVAILABLE = 1.20;
-// 10% didn't work so hot on bonito (with no QP support)
-// 15% is next.. still leaves a few short
-// 20% ? this is on the edge of what I want do do
-
//
// Caller retains ownership of and responsibility for inFormat
//
int VQApply(CodecProperties *codec, vqOps_t *info, AMediaFormat* inFormat, int flags) {
ALOGV("codecName %s inFormat %p flags x%x", codec->getName().c_str(), inFormat, flags);
+ (void) info; // unused for now
int32_t bitRateMode = -1;
if (AMediaFormat_getInt32(inFormat, AMEDIAFORMAT_KEY_BITRATE_MODE, &bitRateMode)
@@ -99,14 +92,16 @@
double minimumBpp = codec->getBpp(width, height);
int64_t bitrateFloor = pixels * minimumBpp;
+ int64_t bitrateCeiling = bitrateFloor * codec->getPhaseOut();
if (bitrateFloor > INT32_MAX) bitrateFloor = INT32_MAX;
+ if (bitrateCeiling > INT32_MAX) bitrateCeiling = INT32_MAX;
// if we are far enough above the target bpp, leave it alone
//
ALOGV("bitrate: configured %" PRId64 " floor %" PRId64, bitrateConfigured, bitrateFloor);
- if (bitrateConfigured >= BITRATE_LEAVE_UNTOUCHED * bitrateFloor) {
- ALOGV("high enough bitrate: configured %" PRId64 " >= %f * floor %" PRId64,
- bitrateConfigured, BITRATE_LEAVE_UNTOUCHED, bitrateFloor);
+ if (bitrateConfigured >= bitrateCeiling) {
+ ALOGV("high enough bitrate: configured %" PRId64 " >= ceiling %" PRId64,
+ bitrateConfigured, bitrateCeiling);
return 0;
}
@@ -117,38 +112,53 @@
bitrateChosen = bitrateFloor;
}
- bool qpPresent = hasQp(inFormat);
+ bool qpPresent = hasQpMax(inFormat);
- // add QP, if not already present
+ // calculate a target QP value
+ int32_t qpmax = codec->targetQpMax();
if (!qpPresent) {
- int32_t qpmax = codec->targetQpMax();
+ // user didn't, so shaper wins
if (qpmax != INT32_MAX) {
ALOGV("choosing qp=%d", qpmax);
qpChosen = qpmax;
}
+ } else if (qpmax == INT32_MAX) {
+ // shaper didn't so user wins
+ qpChosen = INT32_MAX;
+ AMediaFormat_getInt32(inFormat, AMEDIAFORMAT_VIDEO_QP_MAX, &qpChosen);
+ } else {
+ // both sides want it, choose most restrictive
+ int32_t value = INT32_MAX;
+ AMediaFormat_getInt32(inFormat, AMEDIAFORMAT_VIDEO_QP_MAX, &value);
+ qpChosen = std::min(qpmax, value);
}
// if QP is desired but not supported, compensate with additional bits
if (!codec->supportsQp()) {
- if (qpPresent || qpChosen != INT32_MAX) {
- ALOGD("minquality: desired QP, but unsupported, boost bitrate %" PRId64 " to %" PRId64,
- bitrateChosen, (int64_t)(bitrateChosen * BITRATE_QP_UNAVAILABLE));
- bitrateChosen = bitrateChosen * BITRATE_QP_UNAVAILABLE;
+ if (qpChosen != INT32_MAX) {
+ int64_t boost = bitrateChosen * codec->getMissingQpBoost();
+ ALOGD("minquality: requested QP unsupported, boost bitrate %" PRId64 " by %" PRId64,
+ bitrateChosen, boost);
+ bitrateChosen = bitrateChosen + boost;
qpChosen = INT32_MAX;
}
}
+ // limits
// apply our chosen values
//
if (qpChosen != INT32_MAX) {
ALOGD("minquality by QP: inject %s=%d", AMEDIAFORMAT_VIDEO_QP_MAX, qpChosen);
AMediaFormat_setInt32(inFormat, AMEDIAFORMAT_VIDEO_QP_MAX, qpChosen);
- // force spreading the QP across frame types, since we are imposing a value
- qpSpreadMaxPerFrameType(inFormat, info->qpDelta, info->qpMax, /* override */ true);
+ // caller (VideoShaper) handles spreading this across the subframes
}
if (bitrateChosen != bitrateConfigured) {
+ if (bitrateChosen > bitrateCeiling) {
+ ALOGD("minquality: bitrate increase clamped at ceiling %" PRId64, bitrateCeiling);
+ bitrateChosen = bitrateCeiling;
+ }
ALOGD("minquality/target bitrate raised from %" PRId64 " to %" PRId64 " bps",
bitrateConfigured, bitrateChosen);
AMediaFormat_setInt32(inFormat, AMEDIAFORMAT_KEY_BIT_RATE, (int32_t)bitrateChosen);
@@ -158,7 +168,7 @@
}
-bool hasQpPerFrameType(AMediaFormat *format) {
+bool hasQpMaxPerFrameType(AMediaFormat *format) {
int32_t value;
if (AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_I_MAX, &value)
@@ -176,19 +186,29 @@
return false;
}
-bool hasQp(AMediaFormat *format) {
+bool hasQpMaxGlobal(AMediaFormat *format) {
int32_t value;
if (AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_MAX, &value)
|| AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_MIN, &value)) {
return true;
}
- return hasQpPerFrameType(format);
+ return false;
+}
+
+bool hasQpMax(AMediaFormat *format) {
+ if (hasQpMaxGlobal(format)) {
+ return true;
+ }
+ return hasQpMaxPerFrameType(format);
}
void qpSpreadPerFrameType(AMediaFormat *format, int delta,
int qplow, int qphigh, bool override) {
- qpSpreadMaxPerFrameType(format, delta, qphigh, override);
+
qpSpreadMinPerFrameType(format, qplow, override);
+ qpSpreadMaxPerFrameType(format, delta, qphigh, override);
+ // make sure that min<max for all the QP fields.
+ qpVerifyMinMaxOrdering(format);
}
void qpSpreadMaxPerFrameType(AMediaFormat *format, int delta, int qphigh, bool override) {
@@ -196,20 +216,26 @@
int32_t qpOffered = 0;
if (AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_MAX, &qpOffered)) {
- // propagate to otherwise unspecified frame-specific keys
- int32_t maxI;
- if (override || !AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_I_MAX, &maxI)) {
- int32_t value = std::min(qphigh, qpOffered);
+ // propagate to frame-specific keys, choosing most restrictive
+ // ensure that we don't violate min<=max rules
+ {
+ int32_t maxI = INT32_MAX;
+ AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_I_MAX, &maxI);
+ int32_t value = std::min({qpOffered, qphigh, maxI});
AMediaFormat_setInt32(format, AMEDIAFORMAT_VIDEO_QP_I_MAX, value);
}
- int32_t maxP;
- if (override || !AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_P_MAX, &maxP)) {
- int32_t value = std::min(qphigh, (std::min(qpOffered, INT32_MAX-delta) + delta));
+ {
+ int32_t maxP = INT32_MAX;
+ AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_P_MAX, &maxP);
+ int32_t value = std::min({(std::min(qpOffered, INT32_MAX-1*delta) + 1*delta),
+ qphigh, maxP});
AMediaFormat_setInt32(format, AMEDIAFORMAT_VIDEO_QP_P_MAX, value);
}
- int32_t maxB;
- if (override || !AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_B_MAX, &maxB)) {
- int32_t value = std::min(qphigh, (std::min(qpOffered, INT32_MAX-2*delta) + 2*delta));
+ {
+ int32_t maxB = INT32_MAX;
+ AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_B_MAX, &maxB);
+ int32_t value = std::min({(std::min(qpOffered, INT32_MAX-2*delta) + 2*delta),
+ qphigh, maxB});
AMediaFormat_setInt32(format, AMEDIAFORMAT_VIDEO_QP_B_MAX, value);
}
}
@@ -221,19 +247,47 @@
int32_t qpOffered = 0;
if (AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_MIN, &qpOffered)) {
int value = std::max(qplow, qpOffered);
- // propagate to otherwise unspecified frame-specific keys
- int32_t minI;
- if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_I_MIN, &minI)) {
- AMediaFormat_setInt32(format, AMEDIAFORMAT_VIDEO_QP_I_MIN, value);
- }
- int32_t minP;
- if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_P_MIN, &minP)) {
- AMediaFormat_setInt32(format, AMEDIAFORMAT_VIDEO_QP_P_MIN, value);
- }
- int32_t minB;
- if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_B_MIN, &minB)) {
- AMediaFormat_setInt32(format, AMEDIAFORMAT_VIDEO_QP_B_MIN, value);
- }
+ // propagate to frame-specific keys, use lowest of this and existing per-frame value
+ int32_t minI = INT32_MAX;
+ AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_I_MIN, &minI);
+ int32_t setI = std::min(value, minI);
+ AMediaFormat_setInt32(format, AMEDIAFORMAT_VIDEO_QP_I_MIN, setI);
+
+ int32_t minP = INT32_MAX;
+ AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_P_MIN, &minP);
+ int32_t setP = std::min(value, minP);
+ AMediaFormat_setInt32(format, AMEDIAFORMAT_VIDEO_QP_P_MIN, setP);
+
+ int32_t minB = INT32_MAX;
+ AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_B_MIN, &minB);
+ int32_t setB = std::min(value, minB);
+ AMediaFormat_setInt32(format, AMEDIAFORMAT_VIDEO_QP_B_MIN, setB);
+ }
+}
+
+// XXX whether we allow min==max, or if we'll insist that min<max
+void qpVerifyMinMaxOrdering(AMediaFormat *format) {
+ // ensure that we don't violate min<=max rules
+ int32_t maxI = INT32_MAX;
+ int32_t minI = INT32_MIN;
+ if (AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_I_MAX, &maxI)
+ && AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_I_MIN, &minI)
+ && minI > maxI) {
+ AMediaFormat_setInt32(format, AMEDIAFORMAT_VIDEO_QP_I_MIN, maxI);
+ }
+ int32_t maxP = INT32_MAX;
+ int32_t minP = INT32_MIN;
+ if (AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_P_MAX, &maxP)
+ && AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_P_MIN, &minP)
+ && minP > maxP) {
+ AMediaFormat_setInt32(format, AMEDIAFORMAT_VIDEO_QP_P_MIN, maxP);
+ }
+ int32_t maxB = INT32_MAX;
+ int32_t minB = INT32_MIN;
+ if (AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_B_MAX, &maxB)
+ && AMediaFormat_getInt32(format, AMEDIAFORMAT_VIDEO_QP_B_MIN, &minB)
+ && minB > maxB) {
+ AMediaFormat_setInt32(format, AMEDIAFORMAT_VIDEO_QP_B_MIN, maxB);
}
}
diff --git a/media/libmediaformatshaper/include/media/formatshaper/VQops.h b/media/libmediaformatshaper/VQops.h
similarity index 88%
rename from media/libmediaformatshaper/include/media/formatshaper/VQops.h
rename to media/libmediaformatshaper/VQops.h
index 807e8af..74cce18 100644
--- a/media/libmediaformatshaper/include/media/formatshaper/VQops.h
+++ b/media/libmediaformatshaper/VQops.h
@@ -17,7 +17,7 @@
#ifndef LIBMEDIAFORMATSHAPER_VQOPS_H_
#define LIBMEDIAFORMATSHAPER_VQOPS_H_
-#include <media/formatshaper/CodecProperties.h>
+#include "CodecProperties.h"
#include <media/NdkMediaFormat.h>
namespace android {
@@ -39,10 +39,12 @@
void qpSpreadPerFrameType(AMediaFormat *format, int delta, int qplow, int qphigh, bool override);
void qpSpreadMaxPerFrameType(AMediaFormat *format, int delta, int qphigh, bool override);
void qpSpreadMinPerFrameType(AMediaFormat *format, int qplow, bool override);
+void qpVerifyMinMaxOrdering(AMediaFormat *format);
// does the format have QP bounding entries
-bool hasQp(AMediaFormat *format);
-bool hasQpPerFrameType(AMediaFormat *format);
+bool hasQpMax(AMediaFormat *format);
+bool hasQpMaxGlobal(AMediaFormat *format);
+bool hasQpMaxPerFrameType(AMediaFormat *format);
} // namespace mediaformatshaper
} // namespace android
diff --git a/media/libmediaformatshaper/VideoShaper.cpp b/media/libmediaformatshaper/VideoShaper.cpp
index f772a66..cf8b50f 100644
--- a/media/libmediaformatshaper/VideoShaper.cpp
+++ b/media/libmediaformatshaper/VideoShaper.cpp
@@ -23,9 +23,9 @@
#include <media/NdkMediaFormat.h>
-#include <media/formatshaper/VQops.h>
-#include <media/formatshaper/CodecProperties.h>
-#include <media/formatshaper/VideoShaper.h>
+#include "CodecProperties.h"
+#include "VideoShaper.h"
+#include "VQops.h"
namespace android {
namespace mediaformatshaper {
@@ -83,10 +83,10 @@
// apply any quality transforms in here..
(void) VQApply(codec, info, inFormat, flags);
- // We must always spread any QP parameters.
+ // We always spread any QP parameters.
// Sometimes it's something we inserted here, sometimes it's a value that the user injected.
//
- qpSpreadPerFrameType(inFormat, info->qpDelta, info->qpMin, info->qpMax, /* override */ false);
+ qpSpreadPerFrameType(inFormat, info->qpDelta, info->qpMin, info->qpMax, /* override */ true);
//
return 0;
diff --git a/media/libmediaformatshaper/include/media/formatshaper/VideoShaper.h b/media/libmediaformatshaper/VideoShaper.h
similarity index 100%
rename from media/libmediaformatshaper/include/media/formatshaper/VideoShaper.h
rename to media/libmediaformatshaper/VideoShaper.h
diff --git a/media/libmediatranscoding/TranscoderWrapper.cpp b/media/libmediatranscoding/TranscoderWrapper.cpp
index b19e711..5e4c671 100644
--- a/media/libmediatranscoding/TranscoderWrapper.cpp
+++ b/media/libmediatranscoding/TranscoderWrapper.cpp
@@ -23,6 +23,7 @@
#include <media/NdkCommon.h>
#include <media/TranscoderWrapper.h>
#include <media/TranscodingRequest.h>
+#include <utils/AndroidThreads.h>
#include <utils/Log.h>
#include <thread>
@@ -599,6 +600,7 @@
}
void TranscoderWrapper::threadLoop() {
+ androidSetThreadPriority(0 /*tid (0 = current) */, ANDROID_PRIORITY_BACKGROUND);
std::unique_lock<std::mutex> lock{mLock};
// TranscoderWrapper currently lives in the transcoding service, as long as
// MediaTranscodingService itself.
diff --git a/media/libmediatranscoding/TranscodingSessionController.cpp b/media/libmediatranscoding/TranscodingSessionController.cpp
index 68e2875..ea3e518 100644
--- a/media/libmediatranscoding/TranscodingSessionController.cpp
+++ b/media/libmediatranscoding/TranscodingSessionController.cpp
@@ -19,9 +19,11 @@
#define VALIDATE_STATE 1
+#include <android/permission_manager.h>
#include <inttypes.h>
#include <media/TranscodingSessionController.h>
#include <media/TranscodingUidPolicy.h>
+#include <utils/AndroidThreads.h>
#include <utils/Log.h>
#include <thread>
@@ -161,6 +163,7 @@
// Unfortunately std::unique_lock is incompatible with -Wthread-safety.
void TranscodingSessionController::Watchdog::threadLoop() NO_THREAD_SAFETY_ANALYSIS {
+ androidSetThreadPriority(0 /*tid (0 = current) */, ANDROID_PRIORITY_BACKGROUND);
std::unique_lock<std::mutex> lock{mLock};
while (!mAbort) {
@@ -193,7 +196,7 @@
~Pacer() = default;
- bool onSessionStarted(uid_t uid);
+ bool onSessionStarted(uid_t uid, uid_t callingUid);
void onSessionCompleted(uid_t uid, std::chrono::microseconds runningTime);
void onSessionCancelled(uid_t uid);
@@ -212,9 +215,49 @@
std::chrono::steady_clock::time_point lastCompletedTime;
};
std::map<uid_t, UidHistoryEntry> mUidHistoryMap;
+ std::unordered_set<uid_t> mMtpUids;
+ std::unordered_set<uid_t> mNonMtpUids;
+
+ bool isSubjectToQuota(uid_t uid, uid_t callingUid);
};
-bool TranscodingSessionController::Pacer::onSessionStarted(uid_t uid) {
+bool TranscodingSessionController::Pacer::isSubjectToQuota(uid_t uid, uid_t callingUid) {
+ // Submitting with self uid is not limited (which can only happen if it's used as an
+ // app-facing API). MediaProvider usage always submit on behalf of other uids.
+ if (uid == callingUid) {
+ return false;
+ }
+
+ if (mMtpUids.find(uid) != mMtpUids.end()) {
+ return false;
+ }
+
+ if (mNonMtpUids.find(uid) != mNonMtpUids.end()) {
+ return true;
+ }
+
+ // We don't have MTP permission info about this uid yet, check permission and save the result.
+ int32_t result;
+ if (__builtin_available(android __TRANSCODING_MIN_API__, *)) {
+ if (APermissionManager_checkPermission("android.permission.ACCESS_MTP", -1 /*pid*/, uid,
+ &result) == PERMISSION_MANAGER_STATUS_OK &&
+ result == PERMISSION_MANAGER_PERMISSION_GRANTED) {
+ mMtpUids.insert(uid);
+ return false;
+ }
+ }
+
+ mNonMtpUids.insert(uid);
+ return true;
+}
+
+bool TranscodingSessionController::Pacer::onSessionStarted(uid_t uid, uid_t callingUid) {
+ if (!isSubjectToQuota(uid, callingUid)) {
+ ALOGI("Pacer::onSessionStarted: uid %d (caling uid: %d): not subject to quota", uid,
+ callingUid);
+ return true;
+ }
+
// If uid doesn't exist, only insert the entry and mark session active. Skip quota checking.
if (mUidHistoryMap.find(uid) == mUidHistoryMap.end()) {
mUidHistoryMap.emplace(uid, UidHistoryEntry{});
@@ -494,7 +537,7 @@
// Check if at least one client has quota to start the session.
bool keepForClient = false;
for (uid_t uid : topSession->allClientUids) {
- if (mPacer->onSessionStarted(uid)) {
+ if (mPacer->onSessionStarted(uid, topSession->callingUid)) {
keepForClient = true;
// DO NOT break here, because book-keeping still needs to happen
// for the other uids.
diff --git a/media/libmediatranscoding/tests/TranscodingSessionController_tests.cpp b/media/libmediatranscoding/tests/TranscodingSessionController_tests.cpp
index 9e7fa95..ef9c4f8 100644
--- a/media/libmediatranscoding/tests/TranscodingSessionController_tests.cpp
+++ b/media/libmediatranscoding/tests/TranscodingSessionController_tests.cpp
@@ -339,19 +339,37 @@
EXPECT_EQ(mTranscoder.use_count(), 2);
}
- void testPacerHelper(int numSubmits, int sessionDurationMs, int expectedSuccess,
- bool pauseLastSuccessSession = false) {
+ void testPacerHelper(int numSubmits, int sessionDurationMs, int expectedSuccess) {
testPacerHelper(numSubmits, sessionDurationMs, expectedSuccess, mClientCallback0, {},
- pauseLastSuccessSession);
+ false /*pauseLastSuccessSession*/, true /*useRealCallingUid*/);
+ }
+
+ void testPacerHelperWithPause(int numSubmits, int sessionDurationMs, int expectedSuccess) {
+ testPacerHelper(numSubmits, sessionDurationMs, expectedSuccess, mClientCallback0, {},
+ true /*pauseLastSuccessSession*/, true /*useRealCallingUid*/);
+ }
+
+ void testPacerHelperWithMultipleUids(int numSubmits, int sessionDurationMs, int expectedSuccess,
+ const std::shared_ptr<TestClientCallback>& client,
+ const std::vector<int>& additionalClientUids) {
+ testPacerHelper(numSubmits, sessionDurationMs, expectedSuccess, client,
+ additionalClientUids, false /*pauseLastSuccessSession*/,
+ true /*useRealCallingUid*/);
+ }
+
+ void testPacerHelperWithSelfUid(int numSubmits, int sessionDurationMs, int expectedSuccess) {
+ testPacerHelper(numSubmits, sessionDurationMs, expectedSuccess, mClientCallback0, {},
+ false /*pauseLastSuccessSession*/, false /*useRealCallingUid*/);
}
void testPacerHelper(int numSubmits, int sessionDurationMs, int expectedSuccess,
const std::shared_ptr<TestClientCallback>& client,
- const std::vector<int>& additionalClientUids,
- bool pauseLastSuccessSession) {
+ const std::vector<int>& additionalClientUids, bool pauseLastSuccessSession,
+ bool useRealCallingUid) {
+ uid_t callingUid = useRealCallingUid ? ::getuid() : client->clientUid();
for (int i = 0; i < numSubmits; i++) {
- mController->submit(client->clientId(), SESSION(i), client->clientUid(),
- client->clientUid(), mRealtimeRequest, client);
+ mController->submit(client->clientId(), SESSION(i), callingUid, client->clientUid(),
+ mRealtimeRequest, client);
for (int additionalUid : additionalClientUids) {
mController->addClientUid(client->clientId(), SESSION(i), additionalUid);
}
@@ -1294,8 +1312,7 @@
TEST_F(TranscodingSessionControllerTest, TestTranscoderPacerWithPause) {
ALOGD("TestTranscoderPacerDuringPause");
- testPacerHelper(12 /*numSubmits*/, 400 /*sessionDurationMs*/, 10 /*expectedSuccess*/,
- true /*pauseLastSuccessSession*/);
+ testPacerHelperWithPause(12 /*numSubmits*/, 400 /*sessionDurationMs*/, 10 /*expectedSuccess*/);
}
/*
@@ -1305,17 +1322,26 @@
TEST_F(TranscodingSessionControllerTest, TestTranscoderPacerMultipleUids) {
ALOGD("TestTranscoderPacerMultipleUids");
// First, run mClientCallback0 to the point of no quota.
- testPacerHelper(12 /*numSubmits*/, 400 /*sessionDurationMs*/, 10 /*expectedSuccess*/,
- mClientCallback0, {}, false /*pauseLastSuccessSession*/);
+ testPacerHelperWithMultipleUids(12 /*numSubmits*/, 400 /*sessionDurationMs*/,
+ 10 /*expectedSuccess*/, mClientCallback0, {});
// Make UID(0) block on Client1's sessions too, Client1's quota should not be affected.
- testPacerHelper(12 /*numSubmits*/, 400 /*sessionDurationMs*/, 10 /*expectedSuccess*/,
- mClientCallback1, {UID(0)}, false /*pauseLastSuccessSession*/);
+ testPacerHelperWithMultipleUids(12 /*numSubmits*/, 400 /*sessionDurationMs*/,
+ 10 /*expectedSuccess*/, mClientCallback1, {UID(0)});
// Make UID(10) block on Client2's sessions. We expect to see 11 succeeds (instead of 10),
// because the addClientUid() is called after the submit, and first session is already
// started by the time UID(10) is added. UID(10) allowed us to run the 11th session,
// after that both UID(10) and UID(2) are out of quota.
- testPacerHelper(12 /*numSubmits*/, 400 /*sessionDurationMs*/, 11 /*expectedSuccess*/,
- mClientCallback2, {UID(10)}, false /*pauseLastSuccessSession*/);
+ testPacerHelperWithMultipleUids(12 /*numSubmits*/, 400 /*sessionDurationMs*/,
+ 11 /*expectedSuccess*/, mClientCallback2, {UID(10)});
+}
+
+/*
+ * Use same uid for clientUid and callingUid, should not be limited by quota.
+ */
+TEST_F(TranscodingSessionControllerTest, TestTranscoderPacerSelfUid) {
+ ALOGD("TestTranscoderPacerSelfUid");
+ testPacerHelperWithSelfUid(12 /*numSubmits*/, 400 /*sessionDurationMs*/,
+ 12 /*expectedSuccess*/);
}
} // namespace android
diff --git a/media/libmediatranscoding/transcoder/MediaSampleWriter.cpp b/media/libmediatranscoding/transcoder/MediaSampleWriter.cpp
index 10b2e80..e931cc1 100644
--- a/media/libmediatranscoding/transcoder/MediaSampleWriter.cpp
+++ b/media/libmediatranscoding/transcoder/MediaSampleWriter.cpp
@@ -19,7 +19,10 @@
#include <android-base/logging.h>
#include <media/MediaSampleWriter.h>
+#include <media/NdkCommon.h>
#include <media/NdkMediaMuxer.h>
+#include <sys/prctl.h>
+#include <utils/AndroidThreads.h>
namespace android {
@@ -124,7 +127,15 @@
LOG(ERROR) << "Muxer needs to be initialized when adding tracks.";
return nullptr;
}
- ssize_t trackIndexOrError = mMuxer->addTrack(trackFormat.get());
+
+ AMediaFormat* trackFormatCopy = AMediaFormat_new();
+ AMediaFormat_copy(trackFormatCopy, trackFormat.get());
+ // Request muxer to use background priorities by default.
+ AMediaFormatUtils::SetDefaultFormatValueInt32(TBD_AMEDIACODEC_PARAMETER_KEY_BACKGROUND_MODE,
+ trackFormatCopy, 1 /* true */);
+
+ ssize_t trackIndexOrError = mMuxer->addTrack(trackFormatCopy);
+ AMediaFormat_delete(trackFormatCopy);
if (trackIndexOrError < 0) {
LOG(ERROR) << "Failed to add media track to muxer: " << trackIndexOrError;
return nullptr;
@@ -173,6 +184,9 @@
mState = STARTED;
std::thread([this] {
+ androidSetThreadPriority(0 /* tid (0 = current) */, ANDROID_PRIORITY_BACKGROUND);
+ prctl(PR_SET_NAME, (unsigned long)"SampleWriterTrd", 0, 0, 0);
+
bool wasStopped = false;
media_status_t status = writeSamples(&wasStopped);
if (auto callbacks = mCallbacks.lock()) {
diff --git a/media/libmediatranscoding/transcoder/MediaTrackTranscoder.cpp b/media/libmediatranscoding/transcoder/MediaTrackTranscoder.cpp
index 15f7427..f01a948 100644
--- a/media/libmediatranscoding/transcoder/MediaTrackTranscoder.cpp
+++ b/media/libmediatranscoding/transcoder/MediaTrackTranscoder.cpp
@@ -20,6 +20,7 @@
#include <android-base/logging.h>
#include <media/MediaTrackTranscoder.h>
#include <media/MediaTrackTranscoderCallback.h>
+#include <utils/AndroidThreads.h>
namespace android {
@@ -72,6 +73,7 @@
mState = STARTED;
std::thread([this] {
+ androidSetThreadPriority(0 /* tid (0 = current) */, ANDROID_PRIORITY_BACKGROUND);
bool stopped = false;
media_status_t status = runTranscodeLoop(&stopped);
diff --git a/media/libmediatranscoding/transcoder/MediaTranscoder.cpp b/media/libmediatranscoding/transcoder/MediaTranscoder.cpp
index 879241e..e20f7ab 100644
--- a/media/libmediatranscoding/transcoder/MediaTranscoder.cpp
+++ b/media/libmediatranscoding/transcoder/MediaTranscoder.cpp
@@ -25,6 +25,7 @@
#include <media/NdkCommon.h>
#include <media/PassthroughTrackTranscoder.h>
#include <media/VideoTrackTranscoder.h>
+#include <sys/prctl.h>
#include <unistd.h>
namespace android {
@@ -125,6 +126,8 @@
std::thread asyncNotificationThread{[this, self = shared_from_this(),
status = mTranscoderStatus,
stopped = mTranscoderStopped] {
+ prctl(PR_SET_NAME, (unsigned long)"TranscodCallbk", 0, 0, 0);
+
// If the transcoder was stopped that means a caller is waiting in stop or pause
// in which case we don't send a callback.
if (status != AMEDIA_OK) {
diff --git a/media/libmediatranscoding/transcoder/NdkCommon.cpp b/media/libmediatranscoding/transcoder/NdkCommon.cpp
index 2d85df7..e133cd6 100644
--- a/media/libmediatranscoding/transcoder/NdkCommon.cpp
+++ b/media/libmediatranscoding/transcoder/NdkCommon.cpp
@@ -42,6 +42,7 @@
/* TODO(lnilsson): Finalize value or adopt AMediaFormat key once available. */
const char* TBD_AMEDIACODEC_PARAMETER_KEY_COLOR_TRANSFER_REQUEST = "color-transfer-request";
+const char* TBD_AMEDIACODEC_PARAMETER_KEY_BACKGROUND_MODE = "android._background-mode";
namespace AMediaFormatUtils {
diff --git a/media/libmediatranscoding/transcoder/PassthroughTrackTranscoder.cpp b/media/libmediatranscoding/transcoder/PassthroughTrackTranscoder.cpp
index c55e244..3335d6c 100644
--- a/media/libmediatranscoding/transcoder/PassthroughTrackTranscoder.cpp
+++ b/media/libmediatranscoding/transcoder/PassthroughTrackTranscoder.cpp
@@ -19,6 +19,7 @@
#include <android-base/logging.h>
#include <media/PassthroughTrackTranscoder.h>
+#include <sys/prctl.h>
namespace android {
@@ -94,6 +95,8 @@
}
media_status_t PassthroughTrackTranscoder::runTranscodeLoop(bool* stopped) {
+ prctl(PR_SET_NAME, (unsigned long)"PassthruThread", 0, 0, 0);
+
MediaSampleInfo info;
std::shared_ptr<MediaSample> sample;
bool eosReached = false;
diff --git a/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp b/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
index d56bec0..b43efcb 100644
--- a/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
+++ b/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
@@ -21,7 +21,7 @@
#include <android-base/properties.h>
#include <media/NdkCommon.h>
#include <media/VideoTrackTranscoder.h>
-#include <utils/AndroidThreads.h>
+#include <sys/prctl.h>
using namespace AMediaFormatUtils;
@@ -253,6 +253,10 @@
// MediaSampleWriter track format, and MediaSampleWriter will call AMediaMuxer_setOrientationHint.
AMediaFormat_setInt32(encoderFormat, AMEDIAFORMAT_KEY_ROTATION, 0);
+ // Request encoder to use background priorities by default.
+ SetDefaultFormatValueInt32(TBD_AMEDIACODEC_PARAMETER_KEY_BACKGROUND_MODE, encoderFormat,
+ 1 /* true */);
+
mDestinationFormat = std::shared_ptr<AMediaFormat>(encoderFormat, &AMediaFormat_delete);
// Create and configure the encoder.
@@ -334,6 +338,7 @@
static const std::vector<EntryCopier> kEncoderEntriesToCopy{
ENTRY_COPIER2(AMEDIAFORMAT_KEY_OPERATING_RATE, Float, Int32),
ENTRY_COPIER(AMEDIAFORMAT_KEY_PRIORITY, Int32),
+ ENTRY_COPIER(TBD_AMEDIACODEC_PARAMETER_KEY_BACKGROUND_MODE, Int32),
};
CopyFormatEntries(mDestinationFormat.get(), decoderFormat.get(), kEncoderEntriesToCopy);
@@ -588,7 +593,7 @@
}
media_status_t VideoTrackTranscoder::runTranscodeLoop(bool* stopped) {
- androidSetThreadPriority(0 /* tid (0 = current) */, ANDROID_PRIORITY_VIDEO);
+ prctl(PR_SET_NAME, (unsigned long)"VideTranscodTrd", 0, 0, 0);
// Push start decoder and encoder as two messages, so that these are subject to the
// stop request as well. If the session is cancelled (or paused) immediately after start,
diff --git a/media/libmediatranscoding/transcoder/benchmark/MediaTranscoderBenchmark.cpp b/media/libmediatranscoding/transcoder/benchmark/MediaTranscoderBenchmark.cpp
index ac3b2c0..8f8ad4e 100644
--- a/media/libmediatranscoding/transcoder/benchmark/MediaTranscoderBenchmark.cpp
+++ b/media/libmediatranscoding/transcoder/benchmark/MediaTranscoderBenchmark.cpp
@@ -113,6 +113,16 @@
// Asset directory
static const std::string kAssetDirectory = "/data/local/tmp/TranscodingBenchmark/";
+ // Transcoding configuration params to be logged
+ int64_t trackDurationUs = 0;
+ int32_t width = 0;
+ int32_t height = 0;
+ std::string sourceMime = "NA";
+ std::string targetMime = "NA";
+ bool includeAudio = false;
+ bool transcodeVideo = false;
+ int32_t targetBitrate = 0;
+
int srcFd = 0;
int dstFd = 0;
@@ -163,10 +173,30 @@
state.counters[PARAM_VIDEO_FRAME_RATE] = benchmark::Counter(
frameCount, benchmark::Counter::kIsIterationInvariantRate);
}
+ if (!AMediaFormat_getInt32(srcFormat, AMEDIAFORMAT_KEY_WIDTH, &width)) {
+ state.SkipWithError("Video source track format does not have width");
+ goto exit;
+ }
+ if (!AMediaFormat_getInt32(srcFormat, AMEDIAFORMAT_KEY_HEIGHT, &height)) {
+ state.SkipWithError("Video source track format does not have height");
+ goto exit;
+ }
+ AMediaFormat_getInt64(srcFormat, AMEDIAFORMAT_KEY_DURATION, &trackDurationUs);
+ sourceMime = mime;
}
if (trackSelectionCallback(mime, &dstFormat)) {
status = transcoder->configureTrackFormat(i, dstFormat);
+ if (strncmp(mime, "video/", 6) == 0 && dstFormat != nullptr) {
+ const char* mime = nullptr;
+ if (AMediaFormat_getString(dstFormat, AMEDIAFORMAT_KEY_MIME, &mime)) {
+ targetMime = mime;
+ }
+ AMediaFormat_getInt32(dstFormat, AMEDIAFORMAT_KEY_BIT_RATE, &targetBitrate);
+ transcodeVideo = true;
+ } else if (strncmp(mime, "audio/", 6) == 0) {
+ includeAudio = true;
+ }
}
if (dstFormat != nullptr) {
@@ -195,6 +225,17 @@
}
}
+ // Set transcoding configuration params in benchmark label
+ state.SetLabel(srcFileName + "," +
+ std::to_string(width) + "x" + std::to_string(height) + "," +
+ sourceMime + "," +
+ std::to_string(trackDurationUs/1000) + "," +
+ (includeAudio ? "Yes" : "No") + "," +
+ (transcodeVideo ? "Yes" : "No") + "," +
+ targetMime + "," +
+ std::to_string(targetBitrate)
+ );
+
exit:
if (srcFd > 0) close(srcFd);
if (dstFd > 0) close(dstFd);
@@ -543,7 +584,11 @@
void PrintRunData(const Run& report);
bool mPrintedHeader;
- std::vector<std::string> mHeaders = {"name", "real_time", "cpu_time", PARAM_VIDEO_FRAME_RATE};
+ std::vector<std::string> mHeaders = {
+ "File", "Resolution", "SourceMime", "VideoTrackDuration(ms)",
+ "IncludeAudio", "TranscodeVideo", "TargetMime", "TargetBirate(bps)",
+ "real_time(ms)", "cpu_time(ms)", PARAM_VIDEO_FRAME_RATE
+ };
};
bool CustomCsvReporter::ReportContext(const Context& context __unused) {
@@ -574,7 +619,8 @@
return;
}
std::ostream& Out = GetOutputStream();
- Out << run.benchmark_name() << ",";
+ // Log the transcoding params reported through label
+ Out << run.report_label << ",";
Out << run.GetAdjustedRealTime() << ",";
Out << run.GetAdjustedCPUTime() << ",";
auto frameRate = run.counters.find(PARAM_VIDEO_FRAME_RATE);
diff --git a/media/libmediatranscoding/transcoder/include/media/NdkCommon.h b/media/libmediatranscoding/transcoder/include/media/NdkCommon.h
index c5547c6..2441922 100644
--- a/media/libmediatranscoding/transcoder/include/media/NdkCommon.h
+++ b/media/libmediatranscoding/transcoder/include/media/NdkCommon.h
@@ -59,6 +59,7 @@
extern const char* TBD_AMEDIACODEC_PARAMETER_KEY_VIDEO_BITRATE;
extern const char* TBD_AMEDIACODEC_PARAMETER_KEY_MAX_B_FRAMES;
extern const char* TBD_AMEDIACODEC_PARAMETER_KEY_COLOR_TRANSFER_REQUEST;
+extern const char* TBD_AMEDIACODEC_PARAMETER_KEY_BACKGROUND_MODE;
static constexpr int TBD_AMEDIACODEC_BUFFER_FLAG_KEY_FRAME = 0x1;
static constexpr int kBitrateModeConstant = 2;
diff --git a/media/libmediatranscoding/transcoder/tests/MediaSampleWriterTests.cpp b/media/libmediatranscoding/transcoder/tests/MediaSampleWriterTests.cpp
index 8b3905c..0a8a06e 100644
--- a/media/libmediatranscoding/transcoder/tests/MediaSampleWriterTests.cpp
+++ b/media/libmediatranscoding/transcoder/tests/MediaSampleWriterTests.cpp
@@ -117,8 +117,9 @@
}
bool operator==(const TestMuxer::Event& lhs, const TestMuxer::Event& rhs) {
- return lhs.type == rhs.type && lhs.format == rhs.format && lhs.trackIndex == rhs.trackIndex &&
- lhs.data == rhs.data && lhs.info == rhs.info;
+ // Don't test format pointer equality since the writer can make a copy.
+ return lhs.type == rhs.type /*&& lhs.format == rhs.format*/ &&
+ lhs.trackIndex == rhs.trackIndex && lhs.data == rhs.data && lhs.info == rhs.info;
}
/** Represents a media source file. */
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 5c39239..7c7fcac 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -522,6 +522,7 @@
// Reset following variables for all the sessions and they will be
// initialized in start(MetaData *param).
mIsRealTimeRecording = true;
+ mIsBackgroundMode = false;
mUse4ByteNalLength = true;
mOffset = 0;
mMaxOffsetAppend = 0;
@@ -662,6 +663,14 @@
sp<MetaData> meta = source->getFormat();
meta->findCString(kKeyMIMEType, &mime);
+
+ // Background mode for media transcoding. If either audio or video track signal this is in
+ // background mode, we will set all the threads to run in background priority.
+ int32_t isBackgroundMode;
+ if (meta && meta->findInt32(kKeyBackgroundMode, &isBackgroundMode)) {
+ mIsBackgroundMode |= isBackgroundMode;
+ }
+
if (Track::getFourCCForMime(mime) == NULL) {
ALOGE("Unsupported mime '%s'", mime);
return ERROR_UNSUPPORTED;
@@ -2309,7 +2318,11 @@
if (mLooper == nullptr) {
mLooper = new ALooper;
mLooper->setName("MP4WtrCtrlHlpLooper");
- err = mLooper->start();
+ if (mIsBackgroundMode) {
+ err = mLooper->start(false, false, ANDROID_PRIORITY_BACKGROUND);
+ } else {
+ err = mLooper->start();
+ }
mReflector = new AHandlerReflector<MPEG4Writer>(this);
mLooper->registerHandler(mReflector);
}
@@ -2778,6 +2791,11 @@
prctl(PR_SET_NAME, (unsigned long)"MPEG4Writer", 0, 0, 0);
+ if (mIsBackgroundMode) {
+ // Background priority for media transcoding.
+ androidSetThreadPriority(0 /* tid (0 = current) */, ANDROID_PRIORITY_BACKGROUND);
+ }
+
Mutex::Autolock autoLock(mLock);
while (!mDone) {
Chunk chunk;
@@ -3379,6 +3397,9 @@
if (mOwner->isRealTimeRecording()) {
androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);
+ } else if (mOwner->isBackgroundMode()) {
+ // Background priority for media transcoding.
+ androidSetThreadPriority(0 /* tid (0 = current) */, ANDROID_PRIORITY_BACKGROUND);
}
sp<MetaData> meta_data;
@@ -4076,6 +4097,10 @@
return mIsRealTimeRecording;
}
+bool MPEG4Writer::isBackgroundMode() const {
+ return mIsBackgroundMode;
+}
+
bool MPEG4Writer::useNalLengthFour() {
return mUse4ByteNalLength;
}
@@ -5393,4 +5418,4 @@
endBox();
}
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 50ebeef..6b2e7be 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -102,6 +102,17 @@
static const char *kCodecWidth = "android.media.mediacodec.width"; /* 0..n */
static const char *kCodecHeight = "android.media.mediacodec.height"; /* 0..n */
static const char *kCodecRotation = "android.media.mediacodec.rotation-degrees"; /* 0/90/180/270 */
+static const char *kCodecColorFormat = "android.media.mediacodec.color-format";
+static const char *kCodecFrameRate = "android.media.mediacodec.frame-rate";
+static const char *kCodecCaptureRate = "android.media.mediacodec.capture-rate";
+static const char *kCodecOperatingRate = "android.media.mediacodec.operating-rate";
+static const char *kCodecPriority = "android.media.mediacodec.priority";
+static const char *kCodecRequestedVideoQPIMin = "android.media.mediacodec.video-qp-i-min";
+static const char *kCodecRequestedVideoQPIMax = "android.media.mediacodec.video-qp-i-max";
+static const char *kCodecRequestedVideoQPPMin = "android.media.mediacodec.video-qp-p-min";
+static const char *kCodecRequestedVideoQPPMax = "android.media.mediacodec.video-qp-p-max";
+static const char *kCodecRequestedVideoQPBMin = "android.media.mediacodec.video-qp-b-min";
+static const char *kCodecRequestedVideoQPBMax = "android.media.mediacodec.video-qp-b-max";
// NB: These are not yet exposed as public Java API constants.
static const char *kCodecCrypto = "android.media.mediacodec.crypto"; /* 0,1 */
@@ -131,6 +142,8 @@
static const char *kCodecSampleRate = "android.media.mediacodec.sampleRate";
static const char *kCodecVideoEncodedBytes = "android.media.mediacodec.vencode.bytes";
static const char *kCodecVideoEncodedFrames = "android.media.mediacodec.vencode.frames";
+static const char *kCodecVideoInputBytes = "android.media.mediacodec.video.input.bytes";
+static const char *kCodecVideoInputFrames = "android.media.mediacodec.video.input.frames";
static const char *kCodecVideoEncodedDurationUs = "android.media.mediacodec.vencode.durationUs";
// the kCodecRecent* fields appear only in getMetrics() results
@@ -841,6 +854,8 @@
}
mediametrics_setInt64(mMetricsHandle, kCodecVideoEncodedDurationUs, duration);
mediametrics_setInt64(mMetricsHandle, kCodecVideoEncodedFrames, mFramesEncoded);
+ mediametrics_setInt64(mMetricsHandle, kCodecVideoInputFrames, mFramesInput);
+ mediametrics_setInt64(mMetricsHandle, kCodecVideoInputBytes, mBytesInput);
}
{
@@ -1053,7 +1068,7 @@
}
// when we send a buffer to the codec;
-void MediaCodec::statsBufferSent(int64_t presentationUs) {
+void MediaCodec::statsBufferSent(int64_t presentationUs, const sp<MediaCodecBuffer> &buffer) {
// only enqueue if we have a legitimate time
if (presentationUs <= 0) {
@@ -1067,6 +1082,11 @@
});
}
+ if (mIsVideo && (mFlags & kFlagIsEncoder)) {
+ mBytesInput += buffer->size();
+ mFramesInput++;
+ }
+
const int64_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC);
BufferFlightTiming_t startdata = { presentationUs, nowNs };
@@ -1450,6 +1470,50 @@
if (format->findInt32("max-height", &maxHeight)) {
mediametrics_setInt32(mMetricsHandle, kCodecMaxHeight, maxHeight);
}
+ int32_t colorFormat = -1;
+ if (format->findInt32("color-format", &colorFormat)) {
+ mediametrics_setInt32(mMetricsHandle, kCodecColorFormat, colorFormat);
+ }
+ float frameRate = -1.0;
+ if (format->findFloat("frame-rate", &frameRate)) {
+ mediametrics_setDouble(mMetricsHandle, kCodecFrameRate, frameRate);
+ }
+ float captureRate = -1.0;
+ if (format->findFloat("capture-rate", &captureRate)) {
+ mediametrics_setDouble(mMetricsHandle, kCodecCaptureRate, captureRate);
+ }
+ float operatingRate = -1.0;
+ if (format->findFloat("operating-rate", &operatingRate)) {
+ mediametrics_setDouble(mMetricsHandle, kCodecOperatingRate, operatingRate);
+ }
+ int32_t priority = -1;
+ if (format->findInt32("priority", &priority)) {
+ mediametrics_setInt32(mMetricsHandle, kCodecPriority, priority);
+ }
+ int32_t qpIMin = -1;
+ if (format->findInt32("video-qp-i-min", &qpIMin)) {
+ mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPIMin, qpIMin);
+ }
+ int32_t qpIMax = -1;
+ if (format->findInt32("video-qp-i-max", &qpIMax)) {
+ mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPIMax, qpIMax);
+ }
+ int32_t qpPMin = -1;
+ if (format->findInt32("video-qp-p-min", &qpPMin)) {
+ mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPPMin, qpPMin);
+ }
+ int32_t qpPMax = -1;
+ if (format->findInt32("video-qp-p-max", &qpPMax)) {
+ mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPPMax, qpPMax);
+ }
+ int32_t qpBMin = -1;
+ if (format->findInt32("video-qp-b-min", &qpBMin)) {
+ mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPBMin, qpBMin);
+ }
+ int32_t qpBMax = -1;
+ if (format->findInt32("video-qp-b-max", &qpBMax)) {
+ mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPBMax, qpBMax);
+ }
}
// Prevent possible integer overflow in downstream code.
@@ -3518,6 +3582,11 @@
mTunneled = false;
}
+ int32_t background = 0;
+ if (format->findInt32("android._background-mode", &background) && background) {
+ androidSetThreadPriority(gettid(), ANDROID_PRIORITY_BACKGROUND);
+ }
+
mCodec->initiateConfigureComponent(format);
break;
}
@@ -4659,7 +4728,7 @@
info->mOwnedByClient = false;
info->mData.clear();
- statsBufferSent(timeUs);
+ statsBufferSent(timeUs, buffer);
}
return err;
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 04a9b17..4c18f87 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -47,6 +47,16 @@
#include <media/AudioParameter.h>
#include <system/audio.h>
+// TODO : Remove the defines once mainline media is built against NDK >= 31.
+// The mp4 extractor is part of mainline and builds against NDK 29 as of
+// writing. These keys are available only from NDK 31:
+#define AMEDIAFORMAT_KEY_MPEGH_PROFILE_LEVEL_INDICATION \
+ "mpegh-profile-level-indication"
+#define AMEDIAFORMAT_KEY_MPEGH_REFERENCE_CHANNEL_LAYOUT \
+ "mpegh-reference-channel-layout"
+#define AMEDIAFORMAT_KEY_MPEGH_COMPATIBLE_SETS \
+ "mpegh-compatible-sets"
+
namespace android {
static status_t copyNALUToABuffer(sp<ABuffer> *buffer, const uint8_t *ptr, size_t length) {
@@ -1085,6 +1095,25 @@
msg->setInt32("is-adts", isADTS);
}
+ int32_t mpeghProfileLevelIndication;
+ if (meta->findInt32(kKeyMpeghProfileLevelIndication, &mpeghProfileLevelIndication)) {
+ msg->setInt32(AMEDIAFORMAT_KEY_MPEGH_PROFILE_LEVEL_INDICATION,
+ mpeghProfileLevelIndication);
+ }
+ int32_t mpeghReferenceChannelLayout;
+ if (meta->findInt32(kKeyMpeghReferenceChannelLayout, &mpeghReferenceChannelLayout)) {
+ msg->setInt32(AMEDIAFORMAT_KEY_MPEGH_REFERENCE_CHANNEL_LAYOUT,
+ mpeghReferenceChannelLayout);
+ }
+ if (meta->findData(kKeyMpeghCompatibleSets, &type, &data, &size)) {
+ sp<ABuffer> buffer = new (std::nothrow) ABuffer(size);
+ if (buffer.get() == NULL || buffer->base() == NULL) {
+ return NO_MEMORY;
+ }
+ msg->setBuffer(AMEDIAFORMAT_KEY_MPEGH_COMPATIBLE_SETS, buffer);
+ memcpy(buffer->data(), data, size);
+ }
+
int32_t aacProfile = -1;
if (meta->findInt32(kKeyAACAOT, &aacProfile)) {
msg->setInt32("aac-profile", aacProfile);
@@ -1678,7 +1707,7 @@
if (msg->findString("mime", &mime)) {
meta->setCString(kKeyMIMEType, mime.c_str());
} else {
- ALOGI("did not find mime type");
+ ALOGV("did not find mime type");
return BAD_VALUE;
}
@@ -1707,6 +1736,12 @@
meta->setInt32(kKeyIsSyncFrame, 1);
}
+ // Mode for media transcoding.
+ int32_t isBackgroundMode;
+ if (msg->findInt32("android._background-mode", &isBackgroundMode) && isBackgroundMode != 0) {
+ meta->setInt32(isBackgroundMode, 1);
+ }
+
int32_t avgBitrate = 0;
int32_t maxBitrate;
if (msg->findInt32("bitrate", &avgBitrate) && avgBitrate > 0) {
@@ -1728,7 +1763,7 @@
meta->setInt32(kKeyWidth, width);
meta->setInt32(kKeyHeight, height);
} else {
- ALOGI("did not find width and/or height");
+ ALOGV("did not find width and/or height");
return BAD_VALUE;
}
@@ -1817,7 +1852,7 @@
int32_t numChannels, sampleRate;
if (!msg->findInt32("channel-count", &numChannels) ||
!msg->findInt32("sample-rate", &sampleRate)) {
- ALOGI("did not find channel-count and/or sample-rate");
+ ALOGV("did not find channel-count and/or sample-rate");
return BAD_VALUE;
}
meta->setInt32(kKeyChannelCount, numChannels);
@@ -1844,6 +1879,23 @@
meta->setInt32(kKeyIsADTS, isADTS);
}
+ int32_t mpeghProfileLevelIndication = -1;
+ if (msg->findInt32(AMEDIAFORMAT_KEY_MPEGH_PROFILE_LEVEL_INDICATION,
+ &mpeghProfileLevelIndication)) {
+ meta->setInt32(kKeyMpeghProfileLevelIndication, mpeghProfileLevelIndication);
+ }
+ int32_t mpeghReferenceChannelLayout = -1;
+ if (msg->findInt32(AMEDIAFORMAT_KEY_MPEGH_REFERENCE_CHANNEL_LAYOUT,
+ &mpeghReferenceChannelLayout)) {
+ meta->setInt32(kKeyMpeghReferenceChannelLayout, mpeghReferenceChannelLayout);
+ }
+ sp<ABuffer> mpeghCompatibleSets;
+ if (msg->findBuffer(AMEDIAFORMAT_KEY_MPEGH_COMPATIBLE_SETS,
+ &mpeghCompatibleSets)) {
+ meta->setData(kKeyMpeghCompatibleSets, kTypeHCOS,
+ mpeghCompatibleSets->data(), mpeghCompatibleSets->size());
+ }
+
int32_t aacProfile = -1;
if (msg->findInt32("aac-profile", &aacProfile)) {
meta->setInt32(kKeyAACAOT, aacProfile);
diff --git a/media/libstagefright/foundation/Android.bp b/media/libstagefright/foundation/Android.bp
index 7655d90..4bfc673 100644
--- a/media/libstagefright/foundation/Android.bp
+++ b/media/libstagefright/foundation/Android.bp
@@ -45,6 +45,9 @@
],
header_libs: [
+ // this is only needed for the vendor variant that removes libbinder, but vendor
+ // target below does not allow adding header_libs.
+ "libbinder_headers",
"libstagefright_foundation_headers",
"media_ndk_headers",
"media_plugin_headers",
@@ -98,6 +101,7 @@
target: {
vendor: {
+ // TODO: add libbinder_headers here instead of above when it becomes supported
exclude_shared_libs: [
"libbinder",
],
diff --git a/media/libstagefright/foundation/MediaDefs.cpp b/media/libstagefright/foundation/MediaDefs.cpp
index c216bc5..ada5d81 100644
--- a/media/libstagefright/foundation/MediaDefs.cpp
+++ b/media/libstagefright/foundation/MediaDefs.cpp
@@ -58,6 +58,8 @@
const char *MEDIA_MIMETYPE_AUDIO_EAC3 = "audio/eac3";
const char *MEDIA_MIMETYPE_AUDIO_EAC3_JOC = "audio/eac3-joc";
const char *MEDIA_MIMETYPE_AUDIO_AC4 = "audio/ac4";
+const char *MEDIA_MIMETYPE_AUDIO_MPEGH_MHA1 = "audio/mha1";
+const char *MEDIA_MIMETYPE_AUDIO_MPEGH_MHM1 = "audio/mhm1";
const char *MEDIA_MIMETYPE_AUDIO_SCRAMBLED = "audio/scrambled";
const char *MEDIA_MIMETYPE_AUDIO_ALAC = "audio/alac";
const char *MEDIA_MIMETYPE_AUDIO_WMA = "audio/x-ms-wma";
diff --git a/media/libstagefright/foundation/OpusHeader.cpp b/media/libstagefright/foundation/OpusHeader.cpp
index 784e802..30d0ae6 100644
--- a/media/libstagefright/foundation/OpusHeader.cpp
+++ b/media/libstagefright/foundation/OpusHeader.cpp
@@ -146,6 +146,10 @@
int WriteOpusHeader(const OpusHeader &header, int input_sample_rate,
uint8_t* output, size_t output_size) {
// See https://wiki.xiph.org/OggOpus#ID_Header.
+ if (header.channels < 1 || header.channels > kMaxChannels) {
+ ALOGE("Invalid channel count: %d", header.channels);
+ return -1;
+ }
const size_t total_size = kOpusHeaderStreamMapOffset + header.channels;
if (output_size < total_size) {
ALOGE("Output buffer too small for header.");
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h b/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
index e96243e..f5cecef 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
@@ -60,6 +60,8 @@
extern const char *MEDIA_MIMETYPE_AUDIO_EAC3;
extern const char *MEDIA_MIMETYPE_AUDIO_EAC3_JOC;
extern const char *MEDIA_MIMETYPE_AUDIO_AC4;
+extern const char *MEDIA_MIMETYPE_AUDIO_MPEGH_MHA1;
+extern const char *MEDIA_MIMETYPE_AUDIO_MPEGH_MHM1;
extern const char *MEDIA_MIMETYPE_AUDIO_SCRAMBLED;
extern const char *MEDIA_MIMETYPE_AUDIO_ALAC;
extern const char *MEDIA_MIMETYPE_AUDIO_WMA;
@@ -90,6 +92,8 @@
kAudioEncodingPcm16bit = 2,
kAudioEncodingPcm8bit = 3,
kAudioEncodingPcmFloat = 4,
+ kAudioEncodingPcm24bitPacked = 21,
+ kAudioEncodingPcm32bit = 22,
};
} // namespace android
diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
index e97f6eb..b7c9062 100644
--- a/media/libstagefright/id3/ID3.cpp
+++ b/media/libstagefright/id3/ID3.cpp
@@ -234,9 +234,11 @@
}
// first handle global unsynchronization
+ bool hasGlobalUnsync = false;
if (header.flags & 0x80) {
ALOGV("removing unsynchronization");
+ hasGlobalUnsync = true;
removeUnsynchronization();
}
@@ -341,12 +343,12 @@
memcpy(copy, mData, size);
- bool success = removeUnsynchronizationV2_4(false /* iTunesHack */);
+ bool success = removeUnsynchronizationV2_4(false /* iTunesHack */, hasGlobalUnsync);
if (!success) {
memcpy(mData, copy, size);
mSize = size;
- success = removeUnsynchronizationV2_4(true /* iTunesHack */);
+ success = removeUnsynchronizationV2_4(true /* iTunesHack */, hasGlobalUnsync);
if (success) {
ALOGV("Had to apply the iTunes hack to parse this ID3 tag");
@@ -407,7 +409,7 @@
}
}
-bool ID3::removeUnsynchronizationV2_4(bool iTunesHack) {
+bool ID3::removeUnsynchronizationV2_4(bool iTunesHack, bool hasGlobalUnsync) {
size_t oldSize = mSize;
size_t offset = mFirstFrameOffset;
@@ -443,7 +445,7 @@
flags &= ~1;
}
- if ((flags & 2) && (dataSize >= 2)) {
+ if (!hasGlobalUnsync && (flags & 2) && (dataSize >= 2)) {
// This frame has "unsynchronization", so we have to replace occurrences
// of 0xff 0x00 with just 0xff in order to get the real data.
diff --git a/media/libstagefright/id3/test/AndroidTest.xml b/media/libstagefright/id3/test/AndroidTest.xml
index d6ea470..50f9253 100644
--- a/media/libstagefright/id3/test/AndroidTest.xml
+++ b/media/libstagefright/id3/test/AndroidTest.xml
@@ -19,7 +19,7 @@
<option name="cleanup" value="true" />
<option name="push" value="ID3Test->/data/local/tmp/ID3Test" />
<option name="push-file"
- key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/id3/test/ID3Test-1.1.zip?unzip=true"
+ key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/id3/test/ID3Test-1.2.zip?unzip=true"
value="/data/local/tmp/ID3TestRes/" />
</target_preparer>
diff --git a/media/libstagefright/id3/test/ID3Test.cpp b/media/libstagefright/id3/test/ID3Test.cpp
index 8db83cb..1ceeb6a 100644
--- a/media/libstagefright/id3/test/ID3Test.cpp
+++ b/media/libstagefright/id3/test/ID3Test.cpp
@@ -135,6 +135,7 @@
} else {
ASSERT_EQ(data, nullptr) << "Found album art when expected none!";
}
+
#if (LOG_NDEBUG == 0)
hexdump(data, dataSize > 128 ? 128 : dataSize);
#endif
@@ -186,7 +187,8 @@
"bbb_1sec_v23_3tags.mp3",
"bbb_1sec_v1_5tags.mp3",
"bbb_2sec_v24_unsynchronizedOneFrame.mp3",
- "bbb_2sec_v24_unsynchronizedAllFrames.mp3"));
+ "bbb_2sec_v24_unsynchronizedAllFrames.mp3",
+ "idv24_unsynchronized.mp3"));
INSTANTIATE_TEST_SUITE_P(
id3TestAll, ID3versionTest,
@@ -201,7 +203,8 @@
make_pair("bbb_1sec_v1_5tags.mp3", ID3::ID3_V1_1),
make_pair("bbb_1sec_v1_3tags.mp3", ID3::ID3_V1_1),
make_pair("bbb_2sec_v24_unsynchronizedOneFrame.mp3", ID3::ID3_V2_4),
- make_pair("bbb_2sec_v24_unsynchronizedAllFrames.mp3", ID3::ID3_V2_4)));
+ make_pair("bbb_2sec_v24_unsynchronizedAllFrames.mp3", ID3::ID3_V2_4),
+ make_pair("idv24_unsynchronized.mp3", ID3::ID3_V2_4)));
INSTANTIATE_TEST_SUITE_P(
id3TestAll, ID3textTagTest,
@@ -227,7 +230,9 @@
make_pair("bbb_2sec_1_image.mp3", true),
make_pair("bbb_2sec_2_image.mp3", true),
make_pair("bbb_2sec_largeSize.mp3", true),
- make_pair("bbb_1sec_v1_5tags.mp3", false)));
+ make_pair("bbb_1sec_v1_5tags.mp3", false),
+ make_pair("idv24_unsynchronized.mp3", true)
+ ));
INSTANTIATE_TEST_SUITE_P(id3TestAll, ID3multiAlbumArtTest,
::testing::Values(make_pair("bbb_1sec_v23.mp3", 0),
diff --git a/media/libstagefright/include/ID3.h b/media/libstagefright/include/ID3.h
index 0be5896..bd0d27c 100644
--- a/media/libstagefright/include/ID3.h
+++ b/media/libstagefright/include/ID3.h
@@ -91,7 +91,7 @@
bool parseV1(DataSourceBase *source);
bool parseV2(DataSourceBase *source, off64_t offset);
void removeUnsynchronization();
- bool removeUnsynchronizationV2_4(bool iTunesHack);
+ bool removeUnsynchronizationV2_4(bool iTunesHack, bool hasGlobalUnsync);
static bool ParseSyncsafeInteger(const uint8_t encoded[4], size_t *x);
diff --git a/media/libstagefright/include/media/stagefright/MPEG4Writer.h b/media/libstagefright/include/media/stagefright/MPEG4Writer.h
index 7f2728e..7c3eca6 100644
--- a/media/libstagefright/include/media/stagefright/MPEG4Writer.h
+++ b/media/libstagefright/include/media/stagefright/MPEG4Writer.h
@@ -97,6 +97,7 @@
sp<MetaData> mStartMeta;
status_t mInitCheck;
bool mIsRealTimeRecording;
+ bool mIsBackgroundMode;
bool mUse4ByteNalLength;
bool mIsFileSizeLimitExplicitlyRequested;
bool mPaused;
@@ -275,6 +276,10 @@
// By default, real time recording is on.
bool isRealTimeRecording() const;
+ // Return whether the writer is used in background mode for media
+ // transcoding.
+ bool isBackgroundMode() const;
+
void lock();
void unlock();
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index 3f93e6d..0584054 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -572,8 +572,9 @@
int64_t mBytesEncoded = 0;
int64_t mEarliestEncodedPtsUs = INT64_MAX;
int64_t mLatestEncodedPtsUs = INT64_MIN;
- int32_t mFramesEncoded = 0;
-
+ int64_t mFramesEncoded = 0;
+ int64_t mBytesInput = 0;
+ int64_t mFramesInput = 0;
int64_t mNumLowLatencyEnables; // how many times low latency mode is enabled
int64_t mNumLowLatencyDisables; // how many times low latency mode is disabled
@@ -590,7 +591,7 @@
sp<BatteryChecker> mBatteryChecker;
- void statsBufferSent(int64_t presentationUs);
+ void statsBufferSent(int64_t presentationUs, const sp<MediaCodecBuffer> &buffer);
void statsBufferReceived(int64_t presentationUs, const sp<MediaCodecBuffer> &buffer);
enum {
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
index 1a5609a..6371769 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
@@ -684,6 +684,7 @@
constexpr char FEATURE_AdaptivePlayback[] = "adaptive-playback";
constexpr char FEATURE_IntraRefresh[] = "intra-refresh";
constexpr char FEATURE_PartialFrame[] = "partial-frame";
+constexpr char FEATURE_QpBounds[] = "qp-bounds";
constexpr char FEATURE_SecurePlayback[] = "secure-playback";
constexpr char FEATURE_TunneledPlayback[] = "tunneled-playback";
diff --git a/media/libstagefright/include/media/stagefright/MetaDataBase.h b/media/libstagefright/include/media/stagefright/MetaDataBase.h
index 408872f..c80012e 100644
--- a/media/libstagefright/include/media/stagefright/MetaDataBase.h
+++ b/media/libstagefright/include/media/stagefright/MetaDataBase.h
@@ -127,6 +127,8 @@
kKeyTrackTimeStatus = 'tktm', // int64_t
kKeyRealTimeRecording = 'rtrc', // bool (int32_t)
+ kKeyBackgroundMode = 'bkmd', // bool (int32_t)
+
kKeyNumBuffers = 'nbbf', // int32_t
// Ogg files can be tagged to be automatically looping...
@@ -153,6 +155,10 @@
kKeyIsADTS = 'adts', // bool (int32_t)
kKeyAACAOT = 'aaot', // int32_t
+ kKeyMpeghProfileLevelIndication = 'hpli', // int32_t
+ kKeyMpeghReferenceChannelLayout = 'hrcl', // int32_t
+ kKeyMpeghCompatibleSets = 'hcos', // raw data
+
// If a MediaBuffer's data represents (at least partially) encrypted
// data, the following fields aid in decryption.
// The data can be thought of as pairs of plain and encrypted data
@@ -278,6 +284,7 @@
kTypeAV1C = 'av1c',
kTypeDVCC = 'dvcc',
kTypeD263 = 'd263',
+ kTypeHCOS = 'hcos',
};
enum {
diff --git a/media/mediaserver/mediaserver.rc b/media/mediaserver/mediaserver.rc
index c82e532..05373c9 100644
--- a/media/mediaserver/mediaserver.rc
+++ b/media/mediaserver/mediaserver.rc
@@ -7,9 +7,3 @@
group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm
ioprio rt 4
task_profiles ProcessCapacityHigh HighPerformance
-
-# media.transcoding service is defined on com.android.media apex which goes back
-# to API29, but we only want it started on API31+ devices. So we declare it as
-# "disabled" and start it explicitly on boot.
-on boot
- start media.transcoding
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index 3007574..8d527e9 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -85,7 +85,9 @@
cc_library_shared {
name: "libmediandk",
- llndk_stubs: "libmediandk.llndk",
+ llndk: {
+ symbol_file: "libmediandk.map.txt",
+ },
srcs: [
"NdkJavaVMHelper.cpp",
@@ -168,14 +170,6 @@
},
}
-llndk_library {
- name: "libmediandk.llndk",
- symbol_file: "libmediandk.map.txt",
- export_include_dirs: [
- "include",
- ],
-}
-
cc_library {
name: "libmediandk_utils",
diff --git a/media/utils/Android.bp b/media/utils/Android.bp
index 52dc0cf..9e48c1f 100644
--- a/media/utils/Android.bp
+++ b/media/utils/Android.bp
@@ -46,6 +46,7 @@
"libbinder",
"libcutils",
"liblog",
+ "libpermission",
"libutils",
"libhidlbase",
"android.hardware.graphics.bufferqueue@1.0",
diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp
index e2e1043..c19fe38 100644
--- a/media/utils/ServiceUtilities.cpp
+++ b/media/utils/ServiceUtilities.cpp
@@ -114,15 +114,14 @@
if (int32_t mode = appOps.startOpNoThrow(op, identity.uid,
resolvedOpPackageName, /*startIfModeDefault*/ false,
VALUE_OR_FATAL(aidl2legacy_optional_string_view_optional_String16(
- identity.attributionTag)), msg) != AppOpsManager::MODE_ALLOWED) {
+ identity.attributionTag)), msg) == AppOpsManager::MODE_ERRORED) {
ALOGE("Request start for \"%s\" (uid %d) denied by app op: %d, mode: %d",
String8(resolvedOpPackageName).c_str(), identity.uid, op, mode);
return false;
}
} else {
- // Always use OP_RECORD_AUDIO for checks at creation time.
if (int32_t mode = appOps.checkOp(op, uid,
- resolvedOpPackageName) != AppOpsManager::MODE_ALLOWED) {
+ resolvedOpPackageName) == AppOpsManager::MODE_ERRORED) {
ALOGE("Request check for \"%s\" (uid %d) denied by app op: %d, mode: %d",
String8(resolvedOpPackageName).c_str(), identity.uid, op, mode);
return false;
@@ -212,7 +211,6 @@
if (ok) {
static const String16 sCaptureHotwordAllowed("android.permission.CAPTURE_AUDIO_HOTWORD");
- // IMPORTANT: Use PermissionCache - not a runtime permission and may not change.
ok = PermissionCache::checkPermission(sCaptureHotwordAllowed, pid, uid);
}
if (!ok) ALOGV("android.permission.CAPTURE_AUDIO_HOTWORD");
@@ -299,6 +297,10 @@
return identity;
}
+void purgePermissionCache() {
+ PermissionCache::purgeCache();
+}
+
status_t checkIMemory(const sp<IMemory>& iMemory)
{
if (iMemory == 0) {
diff --git a/media/utils/include/mediautils/ServiceUtilities.h b/media/utils/include/mediautils/ServiceUtilities.h
index 9a3c6fb..6e75746 100644
--- a/media/utils/include/mediautils/ServiceUtilities.h
+++ b/media/utils/include/mediautils/ServiceUtilities.h
@@ -97,6 +97,7 @@
bool dumpAllowed();
bool modifyPhoneStateAllowed(const media::permission::Identity& identity);
bool bypassInterruptionPolicyAllowed(const media::permission::Identity& identity);
+void purgePermissionCache();
media::permission::Identity getCallingIdentity();
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 7cdac30..20812bf 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -163,6 +163,33 @@
}
};
+// TODO b/182392769: use identity util
+/* static */
+media::permission::Identity AudioFlinger::checkIdentityPackage(
+ const media::permission::Identity& identity) {
+ Vector<String16> packages;
+ PermissionController{}.getPackagesForUid(identity.uid, packages);
+
+ Identity checkedIdentity = identity;
+ if (!identity.packageName.has_value() || identity.packageName.value().size() == 0) {
+ if (!packages.isEmpty()) {
+ checkedIdentity.packageName =
+ std::move(legacy2aidl_String16_string(packages[0]).value());
+ }
+ } else {
+ String16 opPackageLegacy = VALUE_OR_FATAL(
+ aidl2legacy_string_view_String16(identity.packageName.value_or("")));
+ if (std::find_if(packages.begin(), packages.end(),
+ [&opPackageLegacy](const auto& package) {
+ return opPackageLegacy == package; }) == packages.end()) {
+ ALOGW("The package name(%s) provided does not correspond to the uid %d",
+ identity.packageName.value_or("").c_str(), identity.uid);
+ checkedIdentity.packageName = std::optional<std::string>();
+ }
+ }
+ return checkedIdentity;
+}
+
// ----------------------------------------------------------------------------
std::string formatToString(audio_format_t format) {
@@ -2157,7 +2184,7 @@
&output.notificationFrameCount,
callingPid, adjIdentity, &output.flags,
input.clientInfo.clientTid,
- &lStatus, portId);
+ &lStatus, portId, input.maxSharedAudioHistoryMs);
LOG_ALWAYS_FATAL_IF((lStatus == NO_ERROR) && (recordTrack == 0));
// lStatus == BAD_TYPE means FAST flag was rejected: request a new input from
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index a980752..c66ecb0 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -129,6 +129,9 @@
public:
static void instantiate() ANDROID_API;
+ static media::permission::Identity checkIdentityPackage(
+ const media::permission::Identity& identity);
+
status_t dump(int fd, const Vector<String16>& args) override;
// IAudioFlinger interface, in binder opcode order
@@ -673,6 +676,8 @@
virtual binder::Status setPreferredMicrophoneDirection(
int /*audio_microphone_direction_t*/ direction);
virtual binder::Status setPreferredMicrophoneFieldDimension(float zoom);
+ virtual binder::Status shareAudioHistory(const std::string& sharedAudioPackageName,
+ int64_t sharedAudioStartMs);
private:
const sp<RecordThread::RecordTrack> mRecordTrack;
@@ -978,6 +983,9 @@
std::vector<media::AudioVibratorInfo> mAudioVibratorInfos;
static inline constexpr const char *mMetricsId = AMEDIAMETRICS_KEY_AUDIO_FLINGER;
+
+ // Keep in sync with java definition in media/java/android/media/AudioRecord.java
+ static constexpr int32_t kMaxSharedAudioHistoryMs = 5000;
};
#undef INCLUDING_FROM_AUDIOFLINGER_H
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index 5f248e1..b953c0b 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -69,7 +69,8 @@
const media::permission::Identity& identity,
audio_input_flags_t flags,
track_type type,
- audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE);
+ audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE,
+ int64_t startTimeMs = -1);
virtual ~RecordTrack();
virtual status_t initCheck() const;
@@ -107,6 +108,9 @@
status_t setPreferredMicrophoneDirection(audio_microphone_direction_t direction);
status_t setPreferredMicrophoneFieldDimension(float zoom);
+ status_t shareAudioHistory(const std::string& sharedAudioPackageName,
+ int64_t sharedAudioStartMs);
+ int64_t startTimeMs() { return mStartTimeMs; }
static bool checkServerLatencySupported(
audio_format_t format, audio_input_flags_t flags) {
@@ -146,8 +150,9 @@
bool mSilenced;
// used to enforce OP_RECORD_AUDIO
- uid_t mUid;
sp<OpRecordAudioMonitor> mOpRecordAudioMonitor;
+ std::string mSharedAudioPackageName = {};
+ int64_t mStartTimeMs = -1;
};
// playback track, used by PatchPanel
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 997f24a..6da4543 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -700,6 +700,13 @@
return sendConfigEvent_l(configEvent);
}
+void AudioFlinger::ThreadBase::sendResizeBufferConfigEvent_l(int32_t maxSharedAudioHistoryMs)
+{
+ ALOG_ASSERT(type() == RECORD, "sendResizeBufferConfigEvent_l() called on non record thread");
+ sp<ConfigEvent> configEvent =
+ (ConfigEvent *)new ResizeBufferConfigEvent(maxSharedAudioHistoryMs);
+ sendConfigEvent_l(configEvent);
+}
// post condition: mConfigEvents.isEmpty()
void AudioFlinger::ThreadBase::processConfigEvents_l()
@@ -758,6 +765,11 @@
(UpdateOutDevicesConfigEventData *)event->mData.get();
updateOutDevices(data->mOutDevices);
} break;
+ case CFG_EVENT_RESIZE_BUFFER: {
+ ResizeBufferConfigEventData *data =
+ (ResizeBufferConfigEventData *)event->mData.get();
+ resizeInputBuffer_l(data->mMaxSharedAudioHistoryMs);
+ } break;
default:
ALOG_ASSERT(false, "processConfigEvents_l() unknown event type %d", event->mType);
break;
@@ -1079,6 +1091,11 @@
ALOGE("%s should only be called in RecordThread", __func__);
}
+void AudioFlinger::ThreadBase::resizeInputBuffer_l(int32_t maxSharedAudioHistoryMs __unused)
+{
+ ALOGE("%s should only be called in RecordThread", __func__);
+}
+
void AudioFlinger::ThreadBase::PMDeathRecipient::binderDied(const wp<IBinder>& who __unused)
{
sp<ThreadBase> thread = mThread.promote();
@@ -7766,7 +7783,8 @@
audio_input_flags_t *flags,
pid_t tid,
status_t *status,
- audio_port_handle_t portId)
+ audio_port_handle_t portId,
+ int32_t maxSharedAudioHistoryMs)
{
size_t frameCount = *pFrameCount;
size_t notificationFrameCount = *pNotificationFrameCount;
@@ -7775,6 +7793,7 @@
audio_input_flags_t inputFlags = mInput->flags;
audio_input_flags_t requestedFlags = *flags;
uint32_t sampleRate;
+ Identity checkedIdentity = AudioFlinger::checkIdentityPackage(identity);
lStatus = initCheck();
if (lStatus != NO_ERROR) {
@@ -7788,6 +7807,23 @@
goto Exit;
}
+ if (maxSharedAudioHistoryMs != 0) {
+ if (!captureHotwordAllowed(checkedIdentity)) {
+ lStatus = PERMISSION_DENIED;
+ goto Exit;
+ }
+ //TODO: b/185972521 allow resampling buffer resizing on fast mixers by pausing
+ // the fast mixer thread while resizing the buffer in the normal thread
+ if (hasFastCapture()) {
+ lStatus = BAD_VALUE;
+ goto Exit;
+ }
+ if (maxSharedAudioHistoryMs < 0
+ || maxSharedAudioHistoryMs > AudioFlinger::kMaxSharedAudioHistoryMs) {
+ lStatus = BAD_VALUE;
+ goto Exit;
+ }
+ }
if (*pSampleRate == 0) {
*pSampleRate = mSampleRate;
}
@@ -7896,11 +7932,18 @@
{ // scope for mLock
Mutex::Autolock _l(mLock);
+ long startTimeMs = -1;
+ if (!mSharedAudioPackageName.empty()
+ && mSharedAudioPackageName == checkedIdentity.packageName
+ && mSharedAudioSessionId == sessionId
+ && captureHotwordAllowed(checkedIdentity)) {
+ startTimeMs = mSharedAudioStartMs;
+ }
track = new RecordTrack(this, client, attr, sampleRate,
format, channelMask, frameCount,
nullptr /* buffer */, (size_t)0 /* bufferSize */, sessionId, creatorPid,
- identity, *flags, TrackBase::TYPE_DEFAULT, portId);
+ checkedIdentity, *flags, TrackBase::TYPE_DEFAULT, portId, startTimeMs);
lStatus = track->initCheck();
if (lStatus != NO_ERROR) {
@@ -7916,6 +7959,11 @@
// so ask activity manager to do this on our behalf
sendPrioConfigEvent_l(callingPid, tid, kPriorityAudioApp, true /*forApp*/);
}
+
+ if (maxSharedAudioHistoryMs != 0) {
+ sendResizeBufferConfigEvent_l(maxSharedAudioHistoryMs);
+ }
+
}
lStatus = NO_ERROR;
@@ -8136,6 +8184,37 @@
return mInput->stream->setPreferredMicrophoneFieldDimension(zoom);
}
+status_t AudioFlinger::RecordThread::shareAudioHistory(
+ const std::string& sharedAudioPackageName, audio_session_t sharedSessionId,
+ int64_t sharedAudioStartMs) {
+ AutoMutex _l(mLock);
+ return shareAudioHistory_l(sharedAudioPackageName, sharedSessionId, sharedAudioStartMs);
+}
+
+status_t AudioFlinger::RecordThread::shareAudioHistory_l(
+ const std::string& sharedAudioPackageName, audio_session_t sharedSessionId,
+ int64_t sharedAudioStartMs) {
+ if (hasFastCapture()) {
+ return BAD_VALUE;
+ }
+ if ((hasAudioSession_l(sharedSessionId) & ThreadBase::TRACK_SESSION) == 0) {
+ return BAD_VALUE;
+ }
+ if (sharedAudioStartMs < 0 || sharedAudioStartMs * mSampleRate / 1000 > mRsmpInRear) {
+ return BAD_VALUE;
+ }
+
+ mSharedAudioPackageName = sharedAudioPackageName;
+ if (mSharedAudioPackageName.empty()) {
+ mSharedAudioSessionId = AUDIO_SESSION_NONE;
+ mSharedAudioStartMs = -1;
+ } else {
+ mSharedAudioSessionId = sharedSessionId;
+ mSharedAudioStartMs = sharedAudioStartMs;
+ }
+ return NO_ERROR;
+}
+
void AudioFlinger::RecordThread::updateMetadata_l()
{
if (mInput == nullptr || mInput->stream == nullptr ||
@@ -8167,6 +8246,7 @@
{
track->terminate();
track->mState = TrackBase::STOPPED;
+
// active tracks are removed by threadLoop()
if (mActiveTracks.indexOf(track) < 0) {
removeTrack_l(track);
@@ -8274,8 +8354,23 @@
{
sp<ThreadBase> threadBase = mRecordTrack->mThread.promote();
RecordThread *recordThread = (RecordThread *) threadBase.get();
- mRsmpInFront = recordThread->mRsmpInRear;
mRsmpInUnrel = 0;
+ const int32_t rear = recordThread->mRsmpInRear;
+ ssize_t deltaFrames = 0;
+ if (mRecordTrack->startTimeMs() >= 0) {
+ int32_t startFrames = mRecordTrack->startTimeMs() * recordThread->sampleRate() / 1000;
+ // start frame has to be in the past
+ //TODO: b/185972521 fix in case rear or startFrames wrap around
+ if (startFrames > rear) {
+ startFrames = rear;
+ }
+ deltaFrames = rear - startFrames;
+ // start frame cannot be further in the past than start of resampling buffer
+ if ((size_t) deltaFrames > recordThread->mRsmpInFrames) {
+ deltaFrames = recordThread->mRsmpInFrames;
+ }
+ }
+ mRsmpInFront = audio_utils::safe_sub_overflow(rear, static_cast<int32_t>(deltaFrames));
}
void AudioFlinger::RecordThread::ResamplerBufferProvider::sync(
@@ -8540,31 +8635,10 @@
ALOGV("%p RecordThread params: mChannelCount=%u, mFormat=%#x, mFrameSize=%zu, "
"mBufferSize=%zu, mFrameCount=%zu",
this, mChannelCount, mFormat, mFrameSize, mBufferSize, mFrameCount);
- // This is the formula for calculating the temporary buffer size.
- // With 7 HAL buffers, we can guarantee ability to down-sample the input by ratio of 6:1 to
- // 1 full output buffer, regardless of the alignment of the available input.
- // The value is somewhat arbitrary, and could probably be even larger.
- // A larger value should allow more old data to be read after a track calls start(),
- // without increasing latency.
- //
- // Note this is independent of the maximum downsampling ratio permitted for capture.
- mRsmpInFrames = mFrameCount * 7;
- mRsmpInFramesP2 = roundup(mRsmpInFrames);
- free(mRsmpInBuffer);
- mRsmpInBuffer = NULL;
- // TODO optimize audio capture buffer sizes ...
- // Here we calculate the size of the sliding buffer used as a source
- // for resampling. mRsmpInFramesP2 is currently roundup(mFrameCount * 7).
- // For current HAL frame counts, this is usually 2048 = 40 ms. It would
- // be better to have it derived from the pipe depth in the long term.
- // The current value is higher than necessary. However it should not add to latency.
-
- // Over-allocate beyond mRsmpInFramesP2 to permit a HAL read past end of buffer
- mRsmpInFramesOA = mRsmpInFramesP2 + mFrameCount - 1;
- (void)posix_memalign(&mRsmpInBuffer, 32, mRsmpInFramesOA * mFrameSize);
- // if posix_memalign fails, will segv here.
- memset(mRsmpInBuffer, 0, mRsmpInFramesOA * mFrameSize);
+ // mRsmpInFrames must be 0 before calling resizeInputBuffer_l for the first time
+ mRsmpInFrames = 0;
+ resizeInputBuffer_l();
// AudioRecord mSampleRate and mChannelCount are constant due to AudioRecord API constraints.
// But if thread's mSampleRate or mChannelCount changes, how will that affect active tracks?
@@ -8747,6 +8821,124 @@
}
}
+int32_t AudioFlinger::RecordThread::getOldestFront_l()
+{
+ if (mTracks.size() == 0) {
+ return 0;
+ }
+ //TODO: b/185972521 fix in case of wrap around on one track:
+ // want the max(rear - front) for all tracks.
+ int32_t front = INT_MAX;
+ for (size_t i = 0; i < mTracks.size(); i++) {
+ front = std::min(front, mTracks[i]->mResamplerBufferProvider->getFront());
+ }
+ // discard any audio past the buffer size
+ if (audio_utils::safe_add_overflow(front, (int32_t)mRsmpInFrames) < mRsmpInRear) {
+ front = audio_utils::safe_sub_overflow(mRsmpInRear, (int32_t)mRsmpInFrames);
+ }
+ return front;
+}
+
+void AudioFlinger::RecordThread::updateFronts_l(int32_t offset)
+{
+ if (offset == 0) {
+ return;
+ }
+ for (size_t i = 0; i < mTracks.size(); i++) {
+ int32_t front = mTracks[i]->mResamplerBufferProvider->getFront();
+ front = audio_utils::safe_sub_overflow(front, offset);
+ mTracks[i]->mResamplerBufferProvider->setFront(front);
+ }
+}
+
+void AudioFlinger::RecordThread::resizeInputBuffer_l(int32_t maxSharedAudioHistoryMs)
+{
+ // This is the formula for calculating the temporary buffer size.
+ // With 7 HAL buffers, we can guarantee ability to down-sample the input by ratio of 6:1 to
+ // 1 full output buffer, regardless of the alignment of the available input.
+ // The value is somewhat arbitrary, and could probably be even larger.
+ // A larger value should allow more old data to be read after a track calls start(),
+ // without increasing latency.
+ //
+ // Note this is independent of the maximum downsampling ratio permitted for capture.
+ size_t minRsmpInFrames = mFrameCount * 7;
+
+ // maxSharedAudioHistoryMs != 0 indicates a request to possibly make some part of the audio
+ // capture history available to another client using the same session ID:
+ // dimension the resampler input buffer accordingly.
+
+ // Get oldest client read position: getOldestFront_l() must be called before altering
+ // mRsmpInRear, or mRsmpInFrames
+ int32_t previousFront = getOldestFront_l();
+ size_t previousRsmpInFramesP2 = mRsmpInFramesP2;
+ int32_t previousRear = mRsmpInRear;
+ mRsmpInRear = 0;
+
+ if (maxSharedAudioHistoryMs != 0) {
+ // resizeInputBuffer_l should never be called with a non zero shared history if the
+ // buffer was not already allocated
+ ALOG_ASSERT(mRsmpInBuffer != nullptr && mRsmpInFrames != 0,
+ "resizeInputBuffer_l() called with shared history and unallocated buffer");
+ size_t rsmpInFrames = (size_t)maxSharedAudioHistoryMs * mSampleRate / 1000;
+ // never reduce resampler input buffer size
+ if (rsmpInFrames < mRsmpInFrames) {
+ return;
+ }
+ mRsmpInFrames = rsmpInFrames;
+ }
+ // Note: mRsmpInFrames is 0 when called with maxSharedAudioHistoryMs equals to 0 so it is always
+ // initialized
+ if (mRsmpInFrames < minRsmpInFrames) {
+ mRsmpInFrames = minRsmpInFrames;
+ }
+ mRsmpInFramesP2 = roundup(mRsmpInFrames);
+
+ // TODO optimize audio capture buffer sizes ...
+ // Here we calculate the size of the sliding buffer used as a source
+ // for resampling. mRsmpInFramesP2 is currently roundup(mFrameCount * 7).
+ // For current HAL frame counts, this is usually 2048 = 40 ms. It would
+ // be better to have it derived from the pipe depth in the long term.
+ // The current value is higher than necessary. However it should not add to latency.
+
+ // Over-allocate beyond mRsmpInFramesP2 to permit a HAL read past end of buffer
+ mRsmpInFramesOA = mRsmpInFramesP2 + mFrameCount - 1;
+
+ void *rsmpInBuffer;
+ (void)posix_memalign(&rsmpInBuffer, 32, mRsmpInFramesOA * mFrameSize);
+ // if posix_memalign fails, will segv here.
+ memset(rsmpInBuffer, 0, mRsmpInFramesOA * mFrameSize);
+
+ // Copy audio history if any from old buffer before freeing it
+ if (previousRear != 0) {
+ ALOG_ASSERT(mRsmpInBuffer != nullptr,
+ "resizeInputBuffer_l() called with null buffer but frames already read from HAL");
+
+ ssize_t unread = audio_utils::safe_sub_overflow(previousRear, previousFront);
+ previousFront &= previousRsmpInFramesP2 - 1;
+ size_t part1 = previousRsmpInFramesP2 - previousFront;
+ if (part1 > (size_t) unread) {
+ part1 = unread;
+ }
+ if (part1 != 0) {
+ memcpy(rsmpInBuffer, (const uint8_t*)mRsmpInBuffer + previousFront * mFrameSize,
+ part1 * mFrameSize);
+ mRsmpInRear = part1;
+ part1 = unread - part1;
+ if (part1 != 0) {
+ memcpy((uint8_t*)rsmpInBuffer + mRsmpInRear * mFrameSize,
+ (const uint8_t*)mRsmpInBuffer, part1 * mFrameSize);
+ mRsmpInRear += part1;
+ }
+ }
+ // Update front for all clients according to new rear
+ updateFronts_l(audio_utils::safe_sub_overflow(previousRear, mRsmpInRear));
+ } else {
+ mRsmpInRear = 0;
+ }
+ free(mRsmpInBuffer);
+ mRsmpInBuffer = rsmpInBuffer;
+}
+
void AudioFlinger::RecordThread::addPatchTrack(const sp<PatchRecord>& record)
{
Mutex::Autolock _l(mLock);
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index e63642b..03ed6fd 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -53,6 +53,7 @@
CFG_EVENT_CREATE_AUDIO_PATCH,
CFG_EVENT_RELEASE_AUDIO_PATCH,
CFG_EVENT_UPDATE_OUT_DEVICE,
+ CFG_EVENT_RESIZE_BUFFER
};
class ConfigEventData: public RefBase {
@@ -242,6 +243,28 @@
virtual ~UpdateOutDevicesConfigEvent();
};
+ class ResizeBufferConfigEventData : public ConfigEventData {
+ public:
+ explicit ResizeBufferConfigEventData(int32_t maxSharedAudioHistoryMs) :
+ mMaxSharedAudioHistoryMs(maxSharedAudioHistoryMs) {}
+
+ virtual void dump(char *buffer, size_t size) {
+ snprintf(buffer, size, "mMaxSharedAudioHistoryMs: %d", mMaxSharedAudioHistoryMs);
+ }
+
+ int32_t mMaxSharedAudioHistoryMs;
+ };
+
+ class ResizeBufferConfigEvent : public ConfigEvent {
+ public:
+ explicit ResizeBufferConfigEvent(int32_t maxSharedAudioHistoryMs) :
+ ConfigEvent(CFG_EVENT_RESIZE_BUFFER) {
+ mData = new ResizeBufferConfigEventData(maxSharedAudioHistoryMs);
+ }
+
+ virtual ~ResizeBufferConfigEvent() {}
+ };
+
class PMDeathRecipient : public IBinder::DeathRecipient {
public:
explicit PMDeathRecipient(const wp<ThreadBase>& thread) : mThread(thread) {}
@@ -306,6 +329,7 @@
status_t sendReleaseAudioPatchConfigEvent(audio_patch_handle_t handle);
status_t sendUpdateOutDeviceConfigEvent(
const DeviceDescriptorBaseVector& outDevices);
+ void sendResizeBufferConfigEvent_l(int32_t maxSharedAudioHistoryMs);
void processConfigEvents_l();
virtual void cacheParameters_l() = 0;
virtual status_t createAudioPatch_l(const struct audio_patch *patch,
@@ -314,6 +338,9 @@
virtual void updateOutDevices(const DeviceDescriptorBaseVector& outDevices);
virtual void toAudioPortConfig(struct audio_port_config *config) = 0;
+ virtual void resizeInputBuffer_l(int32_t maxSharedAudioHistoryMs = 0);
+
+
// see note at declaration of mStandby, mOutDevice and mInDevice
bool standby() const { return mStandby; }
@@ -1613,6 +1640,9 @@
// AudioBufferProvider interface
virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
+
+ int32_t getFront() const { return mRsmpInFront; }
+ void setFront(int32_t front) { mRsmpInFront = front; }
private:
RecordTrack * const mRecordTrack;
size_t mRsmpInUnrel; // unreleased frames remaining from
@@ -1662,7 +1692,8 @@
audio_input_flags_t *flags,
pid_t tid,
status_t *status /*non-NULL*/,
- audio_port_handle_t portId);
+ audio_port_handle_t portId,
+ int32_t maxSharedAudioHistoryMs);
status_t start(RecordTrack* recordTrack,
AudioSystem::sync_event_t event,
@@ -1686,6 +1717,7 @@
audio_patch_handle_t *handle);
virtual status_t releaseAudioPatch_l(const audio_patch_handle_t handle);
void updateOutDevices(const DeviceDescriptorBaseVector& outDevices) override;
+ void resizeInputBuffer_l(int32_t maxSharedAudioHistoryMs = 0) override;
void addPatchTrack(const sp<PatchRecord>& record);
void deletePatchTrack(const sp<PatchRecord>& record);
@@ -1741,6 +1773,13 @@
&& inDeviceType() == mTimestampCorrectedDevice;
}
+ status_t shareAudioHistory(const std::string& sharedAudioPackageName,
+ audio_session_t sharedSessionId = AUDIO_SESSION_NONE,
+ int64_t sharedAudioStartMs = -1);
+ status_t shareAudioHistory_l(const std::string& sharedAudioPackageName,
+ audio_session_t sharedSessionId = AUDIO_SESSION_NONE,
+ int64_t sharedAudioStartMs = -1);
+
protected:
void dumpInternals_l(int fd, const Vector<String16>& args) override;
void dumpTracks_l(int fd, const Vector<String16>& args) override;
@@ -1754,6 +1793,9 @@
void checkBtNrec_l();
+ int32_t getOldestFront_l();
+ void updateFronts_l(int32_t offset);
+
AudioStreamIn *mInput;
Source *mSource;
SortedVector < sp<RecordTrack> > mTracks;
@@ -1819,6 +1861,10 @@
int64_t mFramesRead = 0; // continuous running counter.
DeviceDescriptorBaseVector mOutDevices;
+
+ std::string mSharedAudioPackageName = {};
+ long mSharedAudioStartMs = 0;
+ audio_session_t mSharedAudioSessionId = AUDIO_SESSION_NONE;
};
class MmapThread : public ThreadBase
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 21651af..6549236 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -525,31 +525,8 @@
return nullptr;
}
- // TODO b/182392769: use identity util
- std::optional<std::string> opPackageNameStr = identity.packageName;
- if (!identity.packageName.has_value()) {
- // If no package name is provided by the client, use the first associated with the uid
- if (!packages.isEmpty()) {
- opPackageNameStr =
- VALUE_OR_FATAL(legacy2aidl_String16_string(packages[0]));
- }
- } else {
- // If the provided package name is invalid, we force app ops denial by clearing the package
- // name passed to OpPlayAudioMonitor
- String16 opPackageLegacy = VALUE_OR_FATAL(
- aidl2legacy_string_view_String16(opPackageNameStr.value_or("")));
- if (std::find_if(packages.begin(), packages.end(),
- [&opPackageLegacy](const auto& package) {
- return opPackageLegacy == package; }) == packages.end()) {
- ALOGW("The package name(%s) provided does not correspond to the uid %d, "
- "force muting the track", opPackageNameStr.value().c_str(), uid);
- // Set null package name so hasOpPlayAudio will always return false.
- opPackageNameStr = std::optional<std::string>();
- }
- }
- Identity adjIdentity = identity;
- adjIdentity.packageName = opPackageNameStr;
- return new OpPlayAudioMonitor(adjIdentity, attr.usage, id);
+ Identity checkedIdentity = AudioFlinger::checkIdentityPackage(identity);
+ return new OpPlayAudioMonitor(checkedIdentity, attr.usage, id);
}
AudioFlinger::PlaybackThread::OpPlayAudioMonitor::OpPlayAudioMonitor(
@@ -2243,24 +2220,12 @@
return nullptr;
}
- if (!identity.packageName.has_value() || identity.packageName.value().size() == 0) {
- Vector<String16> packages;
- // no package name, happens with SL ES clients
- // query package manager to find one
- PermissionController permissionController;
- permissionController.getPackagesForUid(identity.uid, packages);
- if (packages.isEmpty()) {
- return nullptr;
- } else {
- Identity adjIdentity = identity;
- adjIdentity.packageName =
- VALUE_OR_FATAL(legacy2aidl_String16_string(packages[0]));
- ALOGV("using identity:%s", adjIdentity.toString().c_str());
- return new OpRecordAudioMonitor(adjIdentity);
- }
+ Identity checkedIdentity = AudioFlinger::checkIdentityPackage(identity);
+ if (!checkedIdentity.packageName.has_value()
+ || checkedIdentity.packageName.value().size() == 0) {
+ return nullptr;
}
-
- return new OpRecordAudioMonitor(identity);
+ return new OpRecordAudioMonitor(checkedIdentity);
}
AudioFlinger::RecordThread::OpRecordAudioMonitor::OpRecordAudioMonitor(
@@ -2386,6 +2351,12 @@
return binderStatusFromStatusT(mRecordTrack->setPreferredMicrophoneFieldDimension(zoom));
}
+binder::Status AudioFlinger::RecordHandle::shareAudioHistory(
+ const std::string& sharedAudioPackageName, int64_t sharedAudioStartMs) {
+ return binderStatusFromStatusT(
+ mRecordTrack->shareAudioHistory(sharedAudioPackageName, sharedAudioStartMs));
+}
+
// ----------------------------------------------------------------------------
#undef LOG_TAG
#define LOG_TAG "AF::RecordTrack"
@@ -2406,7 +2377,8 @@
const Identity& identity,
audio_input_flags_t flags,
track_type type,
- audio_port_handle_t portId)
+ audio_port_handle_t portId,
+ int64_t startTimeMs)
: TrackBase(thread, client, attr, sampleRate, format,
channelMask, frameCount, buffer, bufferSize, sessionId,
creatorPid,
@@ -2423,7 +2395,8 @@
mRecordBufferConverter(NULL),
mFlags(flags),
mSilenced(false),
- mOpRecordAudioMonitor(OpRecordAudioMonitor::createIfNeeded(identity, attr))
+ mOpRecordAudioMonitor(OpRecordAudioMonitor::createIfNeeded(identity, attr)),
+ mStartTimeMs(startTimeMs)
{
if (mCblk == NULL) {
return;
@@ -2533,6 +2506,9 @@
Mutex::Autolock _l(thread->mLock);
RecordThread *recordThread = (RecordThread *) thread.get();
priorState = mState;
+ if (!mSharedAudioPackageName.empty()) {
+ recordThread->shareAudioHistory_l("");
+ }
recordThread->destroyTrack_l(this); // move mState to STOPPED, terminate
}
// APM portid/client management done outside of lock.
@@ -2719,6 +2695,37 @@
}
}
+status_t AudioFlinger::RecordThread::RecordTrack::shareAudioHistory(
+ const std::string& sharedAudioPackageName, int64_t sharedAudioStartMs) {
+
+ const uid_t callingUid = IPCThreadState::self()->getCallingUid();
+ const pid_t callingPid = IPCThreadState::self()->getCallingPid();
+ if (callingUid != mUid || callingPid != mCreatorPid) {
+ return PERMISSION_DENIED;
+ }
+
+ Identity identity{};
+ identity.uid = VALUE_OR_RETURN_STATUS(legacy2aidl_uid_t_int32_t(callingUid));
+ identity.pid = VALUE_OR_RETURN_STATUS(legacy2aidl_uid_t_int32_t(callingPid));
+ if (!captureHotwordAllowed(identity)) {
+ return PERMISSION_DENIED;
+ }
+
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread != 0) {
+ RecordThread *recordThread = (RecordThread *)thread.get();
+ status_t status = recordThread->shareAudioHistory(
+ sharedAudioPackageName, mSessionId, sharedAudioStartMs);
+ if (status == NO_ERROR) {
+ mSharedAudioPackageName = sharedAudioPackageName;
+ }
+ return status;
+ } else {
+ return BAD_VALUE;
+ }
+}
+
+
// ----------------------------------------------------------------------------
#undef LOG_TAG
#define LOG_TAG "AF::PatchRecord"
diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
index 562c213..84ed656 100644
--- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
@@ -253,6 +253,18 @@
// Children: ModulesTraits, VolumeTraits, SurroundSoundTraits (optional)
};
+// Deleter using free() for use with std::unique_ptr<>. See also UniqueCPtr<> below.
+struct FreeDelete {
+ // NOTE: Deleting a const object is valid but free() takes a non-const pointer.
+ void operator()(const void* ptr) const {
+ free(const_cast<void*>(ptr));
+ }
+};
+
+// Alias for std::unique_ptr<> that uses the C function free() to delete objects.
+template <typename T>
+using UniqueCPtr = std::unique_ptr<T, FreeDelete>;
+
template <class T>
constexpr void (*xmlDeleter)(T* t);
template <>
@@ -608,7 +620,7 @@
}
// Tokenize and Convert Sources name to port pointer
PolicyAudioPortVector sources;
- std::unique_ptr<char[]> sourcesLiteral{strndup(
+ UniqueCPtr<char> sourcesLiteral{strndup(
sourcesAttr.c_str(), strlen(sourcesAttr.c_str()))};
char *devTag = strtok(sourcesLiteral.get(), ",");
while (devTag != NULL) {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index dd44c54..485188a 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -2229,7 +2229,8 @@
// Prevent from storing invalid requested device id in clients
requestedDeviceId = AUDIO_PORT_HANDLE_NONE;
device = mEngine->getInputDeviceForAttributes(attributes, uid, &policyMix);
- ALOGV("%s found device type is 0x%X", __FUNCTION__, device->type());
+ ALOGV_IF(device != nullptr, "%s found device type is 0x%X",
+ __FUNCTION__, device->type());
}
if (device == nullptr) {
ALOGW("getInputForAttr() could not find device for source %d", attributes.source);
@@ -2347,6 +2348,21 @@
return input;
}
+ // Reuse an already opened input if a client with the same session ID already exists
+ // on that input
+ for (size_t i = 0; i < mInputs.size(); i++) {
+ sp <AudioInputDescriptor> desc = mInputs.valueAt(i);
+ if (desc->mProfile != profile) {
+ continue;
+ }
+ RecordClientVector clients = desc->clientsList();
+ for (const auto &client : clients) {
+ if (session == client->session()) {
+ return desc->mIoHandle;
+ }
+ }
+ }
+
if (!profile->canOpenNewIo()) {
for (size_t i = 0; i < mInputs.size(); ) {
sp<AudioInputDescriptor> desc = mInputs.valueAt(i);
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index b5eb98f..fb38e3d 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -1019,6 +1019,9 @@
return handleResetUidState(args, err);
} else if (args.size() >= 2 && args[0] == String16("get-uid-state")) {
return handleGetUidState(args, out, err);
+ } else if (args.size() >= 1 && args[0] == String16("purge_permission-cache")) {
+ purgePermissionCache();
+ return NO_ERROR;
} else if (args.size() == 1 && args[0] == String16("help")) {
printHelp(out);
return NO_ERROR;
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp
index 32c0267..07c889b 100644
--- a/services/camera/libcameraservice/Android.bp
+++ b/services/camera/libcameraservice/Android.bp
@@ -114,6 +114,7 @@
"libutils",
"libbinder",
"libactivitymanager_aidl",
+ "libpermission",
"libcutils",
"libmedia",
"libmediautils",
@@ -163,6 +164,7 @@
export_shared_lib_headers: [
"libbinder",
"libactivitymanager_aidl",
+ "libpermission",
"libcamera_client",
"libfmq",
"libsensorprivacy",
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 6efb90b..3e6a7c7 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -29,7 +29,6 @@
#include <inttypes.h>
#include <pthread.h>
-#include <android/content/pm/IPackageManagerNative.h>
#include <android/hardware/ICamera.h>
#include <android/hardware/ICameraClient.h>
@@ -92,6 +91,8 @@
using hardware::ICameraServiceListener;
using hardware::camera::common::V1_0::CameraDeviceStatus;
using hardware::camera::common::V1_0::TorchModeStatus;
+using hardware::camera2::ICameraInjectionCallback;
+using hardware::camera2::ICameraInjectionSession;
using hardware::camera2::utils::CameraIdAndSessionConfiguration;
using hardware::camera2::utils::ConcurrentCameraIdCombination;
@@ -128,6 +129,8 @@
sCameraSendSystemEventsPermission("android.permission.CAMERA_SEND_SYSTEM_EVENTS");
static const String16 sCameraOpenCloseListenerPermission(
"android.permission.CAMERA_OPEN_CLOSE_LISTENER");
+static const String16
+ sCameraInjectExternalCameraPermission("android.permission.CAMERA_INJECT_EXTERNAL_CAMERA");
static constexpr int32_t kVendorClientScore = resource_policy::PERCEPTIBLE_APP_ADJ;
static constexpr int32_t kVendorClientState = ActivityManager::PROCESS_STATE_PERSISTENT_UI;
@@ -146,6 +149,7 @@
void CameraService::onFirstRef()
{
+
ALOGI("CameraService process starting");
BnCameraService::onFirstRef();
@@ -166,6 +170,7 @@
mUidPolicy->registerSelf();
mSensorPrivacyPolicy = new SensorPrivacyPolicy(this);
mSensorPrivacyPolicy->registerSelf();
+ mInjectionStatusListener = new InjectionStatusListener(this);
mAppOps.setCameraAudioRestriction(mAudioRestriction);
sp<HidlCameraService> hcs = HidlCameraService::getInstance(this);
if (hcs->registerAsService() != android::OK) {
@@ -243,6 +248,7 @@
VendorTagDescriptor::clearGlobalVendorTagDescriptor();
mUidPolicy->unregisterSelf();
mSensorPrivacyPolicy->unregisterSelf();
+ mInjectionStatusListener->removeListener();
}
void CameraService::onNewProviderRegistered() {
@@ -752,6 +758,10 @@
return Status::ok();
}
+void CameraService::clearCachedVariables() {
+ BasicClient::BasicClient::sCameraService = nullptr;
+}
+
int CameraService::getDeviceVersion(const String8& cameraId, int* facing, int* orientation) {
ATRACE_CALL();
@@ -2154,10 +2164,15 @@
return addListenerHelper(listener, cameraStatuses);
}
+binder::Status CameraService::addListenerTest(const sp<hardware::ICameraServiceListener>& listener,
+ std::vector<hardware::CameraStatus>* cameraStatuses) {
+ return addListenerHelper(listener, cameraStatuses, false, true);
+}
+
Status CameraService::addListenerHelper(const sp<ICameraServiceListener>& listener,
/*out*/
std::vector<hardware::CameraStatus> *cameraStatuses,
- bool isVendorListener) {
+ bool isVendorListener, bool isProcessLocalTest) {
ATRACE_CALL();
@@ -2188,7 +2203,7 @@
sp<ServiceListener> serviceListener =
new ServiceListener(this, listener, clientUid, clientPid, isVendorListener,
openCloseCallbackAllowed);
- auto ret = serviceListener->initialize();
+ auto ret = serviceListener->initialize(isProcessLocalTest);
if (ret != NO_ERROR) {
String8 msg = String8::format("Failed to initialize service listener: %s (%d)",
strerror(-ret), ret);
@@ -2377,6 +2392,42 @@
return Status::ok();
}
+Status CameraService::injectCamera(
+ const String16& packageName, const String16& internalCamId,
+ const String16& externalCamId,
+ const sp<ICameraInjectionCallback>& callback,
+ /*out*/
+ sp<hardware::camera2::ICameraInjectionSession>* cameraInjectionSession) {
+ ATRACE_CALL();
+
+ if (!checkCallingPermission(sCameraInjectExternalCameraPermission)) {
+ const int pid = CameraThreadState::getCallingPid();
+ const int uid = CameraThreadState::getCallingUid();
+ ALOGE("Permission Denial: can't inject camera pid=%d, uid=%d", pid, uid);
+ return STATUS_ERROR(ERROR_PERMISSION_DENIED,
+ "Permission Denial: no permission to inject camera");
+ }
+
+ ALOGV(
+ "%s: Package name = %s, Internal camera ID = %s, External camera ID = "
+ "%s",
+ __FUNCTION__, String8(packageName).string(),
+ String8(internalCamId).string(), String8(externalCamId).string());
+
+ binder::Status ret = binder::Status::ok();
+ // TODO: Implement the injection camera function.
+ // ret = internalInjectCamera(...);
+ // if(!ret.isOk()) {
+ // mInjectionStatusListener->notifyInjectionError(...);
+ // return ret;
+ // }
+
+ mInjectionStatusListener->addListener(callback);
+ *cameraInjectionSession = new CameraInjectionSession(this);
+
+ return ret;
+}
+
void CameraService::removeByClient(const BasicClient* client) {
Mutex::Autolock lock(mServiceLock);
for (auto& i : mActiveClientManager.getAll()) {
@@ -2715,6 +2766,11 @@
ATRACE_CALL();
LOG1("playSound(%d)", kind);
+ if (kind < 0 || kind >= NUM_SOUNDS) {
+ ALOGE("%s: Invalid sound id requested: %d", __FUNCTION__, kind);
+ return;
+ }
+
Mutex::Autolock lock(mSoundLock);
loadSoundLocked(kind);
sp<MediaPlayer> player = mSoundPlayer[kind];
@@ -2770,19 +2826,20 @@
const String8& cameraIdStr, int cameraFacing, int sensorOrientation,
int clientPid, uid_t clientUid,
int servicePid):
+ mDestructionStarted(false),
mCameraIdStr(cameraIdStr), mCameraFacing(cameraFacing), mOrientation(sensorOrientation),
mClientPackageName(clientPackageName), mClientFeatureId(clientFeatureId),
mClientPid(clientPid), mClientUid(clientUid),
mServicePid(servicePid),
mDisconnected(false), mUidIsTrusted(false),
mAudioRestriction(hardware::camera2::ICameraDeviceUser::AUDIO_RESTRICTION_NONE),
- mRemoteBinder(remoteCallback)
+ mRemoteBinder(remoteCallback),
+ mOpsActive(false),
+ mOpsStreaming(false)
{
if (sCameraService == nullptr) {
sCameraService = cameraService;
}
- mOpsActive = false;
- mDestructionStarted = false;
// In some cases the calling code has no access to the package it runs under.
// For example, NDK camera API.
@@ -2917,6 +2974,29 @@
}
}
+status_t CameraService::BasicClient::handleAppOpMode(int32_t mode) {
+ if (mode == AppOpsManager::MODE_ERRORED) {
+ ALOGI("Camera %s: Access for \"%s\" has been revoked",
+ mCameraIdStr.string(), String8(mClientPackageName).string());
+ return PERMISSION_DENIED;
+ } else if (!mUidIsTrusted && mode == AppOpsManager::MODE_IGNORED) {
+ // If the calling Uid is trusted (a native service), the AppOpsManager could
+ // return MODE_IGNORED. Do not treat such case as error.
+ bool isUidActive = sCameraService->mUidPolicy->isUidActive(mClientUid,
+ mClientPackageName);
+ bool isCameraPrivacyEnabled =
+ sCameraService->mSensorPrivacyPolicy->isCameraPrivacyEnabled(
+ multiuser_get_user_id(mClientUid));
+ if (!isUidActive || !isCameraPrivacyEnabled) {
+ ALOGI("Camera %s: Access for \"%s\" has been restricted",
+ mCameraIdStr.string(), String8(mClientPackageName).string());
+ // Return the same error as for device policy manager rejection
+ return -EACCES;
+ }
+ }
+ return OK;
+}
+
status_t CameraService::BasicClient::startCameraOps() {
ATRACE_CALL();
@@ -2927,33 +3007,16 @@
if (mAppOpsManager != nullptr) {
// Notify app ops that the camera is not available
mOpsCallback = new OpsCallback(this);
- int32_t res;
mAppOpsManager->startWatchingMode(AppOpsManager::OP_CAMERA,
mClientPackageName, mOpsCallback);
- res = mAppOpsManager->startOpNoThrow(AppOpsManager::OP_CAMERA, mClientUid,
- mClientPackageName, /*startIfModeDefault*/ false, mClientFeatureId,
- String16("start camera ") + String16(mCameraIdStr));
- if (res == AppOpsManager::MODE_ERRORED) {
- ALOGI("Camera %s: Access for \"%s\" has been revoked",
- mCameraIdStr.string(), String8(mClientPackageName).string());
- return PERMISSION_DENIED;
- }
-
- // If the calling Uid is trusted (a native service), the AppOpsManager could
- // return MODE_IGNORED. Do not treat such case as error.
- if (!mUidIsTrusted && res == AppOpsManager::MODE_IGNORED) {
- bool isUidActive = sCameraService->mUidPolicy->isUidActive(mClientUid,
- mClientPackageName);
- bool isCameraPrivacyEnabled =
- sCameraService->mSensorPrivacyPolicy->isCameraPrivacyEnabled(
- multiuser_get_user_id(mClientUid));
- if (!isUidActive || !isCameraPrivacyEnabled) {
- ALOGI("Camera %s: Access for \"%s\" has been restricted",
- mCameraIdStr.string(), String8(mClientPackageName).string());
- // Return the same error as for device policy manager rejection
- return -EACCES;
- }
+ // Just check for camera acccess here on open - delay startOp until
+ // camera frames start streaming in startCameraStreamingOps
+ int32_t mode = mAppOpsManager->checkOp(AppOpsManager::OP_CAMERA, mClientUid,
+ mClientPackageName);
+ status_t res = handleAppOpMode(mode);
+ if (res != OK) {
+ return res;
}
}
@@ -2970,17 +3033,69 @@
return OK;
}
+status_t CameraService::BasicClient::startCameraStreamingOps() {
+ ATRACE_CALL();
+
+ if (!mOpsActive) {
+ ALOGE("%s: Calling streaming start when not yet active", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ if (mOpsStreaming) {
+ ALOGV("%s: Streaming already active!", __FUNCTION__);
+ return OK;
+ }
+
+ ALOGV("%s: Start camera streaming ops, package name = %s, client UID = %d",
+ __FUNCTION__, String8(mClientPackageName).string(), mClientUid);
+
+ if (mAppOpsManager != nullptr) {
+ int32_t mode = mAppOpsManager->startOpNoThrow(AppOpsManager::OP_CAMERA, mClientUid,
+ mClientPackageName, /*startIfModeDefault*/ false, mClientFeatureId,
+ String16("start camera ") + String16(mCameraIdStr));
+ status_t res = handleAppOpMode(mode);
+ if (res != OK) {
+ return res;
+ }
+ }
+
+ mOpsStreaming = true;
+
+ return OK;
+}
+
+status_t CameraService::BasicClient::finishCameraStreamingOps() {
+ ATRACE_CALL();
+
+ if (!mOpsActive) {
+ ALOGE("%s: Calling streaming start when not yet active", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ if (!mOpsStreaming) {
+ ALOGV("%s: Streaming not active!", __FUNCTION__);
+ return OK;
+ }
+
+ if (mAppOpsManager != nullptr) {
+ mAppOpsManager->finishOp(AppOpsManager::OP_CAMERA, mClientUid,
+ mClientPackageName, mClientFeatureId);
+ mOpsStreaming = false;
+ }
+
+ return OK;
+}
+
status_t CameraService::BasicClient::finishCameraOps() {
ATRACE_CALL();
+ if (mOpsStreaming) {
+ // Make sure we've notified everyone about camera stopping
+ finishCameraStreamingOps();
+ }
+
// Check if startCameraOps succeeded, and if so, finish the camera op
if (mOpsActive) {
- // Notify app ops that the camera is available again
- if (mAppOpsManager != nullptr) {
- mAppOpsManager->finishOp(AppOpsManager::OP_CAMERA, mClientUid,
- mClientPackageName, mClientFeatureId);
- mOpsActive = false;
- }
+ mOpsActive = false;
+
// This function is called when a client disconnects. This should
// release the camera, but actually only if it was in a proper
// functional state, i.e. with status NOT_AVAILABLE
@@ -3372,28 +3487,7 @@
}
bool CameraService::SensorPrivacyPolicy::hasCameraPrivacyFeature() {
- if (!mNeedToCheckCameraPrivacyFeature) {
- return mHasCameraPrivacyFeature;
- }
- bool hasCameraPrivacyFeature = false;
- sp<IBinder> binder = defaultServiceManager()->getService(String16("package_native"));
- if (binder != nullptr) {
- sp<content::pm::IPackageManagerNative> packageManager =
- interface_cast<content::pm::IPackageManagerNative>(binder);
- if (packageManager != nullptr) {
- binder::Status status = packageManager->hasSystemFeature(
- String16("android.hardware.camera.toggle"), 0, &hasCameraPrivacyFeature);
-
- if (status.isOk()) {
- mNeedToCheckCameraPrivacyFeature = false;
- mHasCameraPrivacyFeature = hasCameraPrivacyFeature;
- } else {
- ALOGE("Unable to check if camera privacy feature is supported");
- }
- }
- }
-
- return hasCameraPrivacyFeature;
+ return mSpm.supportsSensorToggle(SensorPrivacyManager::INDIVIDUAL_SENSOR_CAMERA);
}
// ----------------------------------------------------------------------------
@@ -3562,6 +3656,66 @@
}
// ----------------------------------------------------------------------------
+// InjectionStatusListener
+// ----------------------------------------------------------------------------
+
+void CameraService::InjectionStatusListener::addListener(
+ const sp<ICameraInjectionCallback>& callback) {
+ Mutex::Autolock lock(mListenerLock);
+ if (mCameraInjectionCallback) return;
+ status_t res = IInterface::asBinder(callback)->linkToDeath(this);
+ if (res == OK) {
+ mCameraInjectionCallback = callback;
+ }
+}
+
+void CameraService::InjectionStatusListener::removeListener() {
+ Mutex::Autolock lock(mListenerLock);
+ if (mCameraInjectionCallback == nullptr) {
+ ALOGW("InjectionStatusListener: mCameraInjectionCallback == nullptr");
+ return;
+ }
+ IInterface::asBinder(mCameraInjectionCallback)->unlinkToDeath(this);
+ mCameraInjectionCallback = nullptr;
+}
+
+void CameraService::InjectionStatusListener::notifyInjectionError(
+ int errorCode) {
+ Mutex::Autolock lock(mListenerLock);
+ if (mCameraInjectionCallback == nullptr) {
+ ALOGW("InjectionStatusListener: mCameraInjectionCallback == nullptr");
+ return;
+ }
+ mCameraInjectionCallback->onInjectionError(errorCode);
+}
+
+void CameraService::InjectionStatusListener::binderDied(
+ const wp<IBinder>& /*who*/) {
+ Mutex::Autolock lock(mListenerLock);
+ ALOGV("InjectionStatusListener: ICameraInjectionCallback has died");
+ auto parent = mParent.promote();
+ if (parent != nullptr) {
+ parent->stopInjectionImpl();
+ }
+}
+
+// ----------------------------------------------------------------------------
+// CameraInjectionSession
+// ----------------------------------------------------------------------------
+
+binder::Status CameraService::CameraInjectionSession::stopInjection() {
+ Mutex::Autolock lock(mInjectionSessionLock);
+ auto parent = mParent.promote();
+ if (parent == nullptr) {
+ ALOGE("CameraInjectionSession: Parent is gone");
+ return STATUS_ERROR(ICameraInjectionCallback::ERROR_INJECTION_SERVICE,
+ "Camera service encountered error");
+ }
+ parent->stopInjectionImpl();
+ return binder::Status::ok();
+}
+
+// ----------------------------------------------------------------------------
static const int kDumpLockRetries = 50;
static const int kDumpLockSleep = 60000;
@@ -4221,4 +4375,10 @@
return mode;
}
+void CameraService::stopInjectionImpl() {
+ mInjectionStatusListener->removeListener();
+
+ // TODO: Implement the stop injection function.
+}
+
}; // namespace android
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 6317c7a..10e1748 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -20,6 +20,8 @@
#include <android/hardware/BnCameraService.h>
#include <android/hardware/BnSensorPrivacyListener.h>
#include <android/hardware/ICameraServiceListener.h>
+#include <android/hardware/camera2/BnCameraInjectionSession.h>
+#include <android/hardware/camera2/ICameraInjectionCallback.h>
#include <cutils/multiuser.h>
#include <utils/Vector.h>
@@ -180,6 +182,13 @@
/*out*/
bool *isSupported);
+ virtual binder::Status injectCamera(
+ const String16& packageName, const String16& internalCamId,
+ const String16& externalCamId,
+ const sp<hardware::camera2::ICameraInjectionCallback>& callback,
+ /*out*/
+ sp<hardware::camera2::ICameraInjectionSession>* cameraInjectionSession);
+
// Extra permissions checks
virtual status_t onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags);
@@ -190,7 +199,8 @@
binder::Status addListenerHelper(const sp<hardware::ICameraServiceListener>& listener,
/*out*/
- std::vector<hardware::CameraStatus>* cameraStatuses, bool isVendor = false);
+ std::vector<hardware::CameraStatus>* cameraStatuses, bool isVendor = false,
+ bool isProcessLocalTest = false);
// Monitored UIDs availability notification
void notifyMonitoredUids();
@@ -219,6 +229,19 @@
int* orientation = nullptr);
/////////////////////////////////////////////////////////////////////
+ // Methods to be used in CameraService class tests only
+ //
+ // CameraService class test method only - clear static variables in the
+ // cameraserver process, which otherwise might affect multiple test runs.
+ void clearCachedVariables();
+
+ // Add test listener, linkToDeath won't be called since this is for process
+ // local testing.
+ binder::Status addListenerTest(const sp<hardware::ICameraServiceListener>& listener,
+ /*out*/
+ std::vector<hardware::CameraStatus>* cameraStatuses);
+
+ /////////////////////////////////////////////////////////////////////
// Shared utilities
static binder::Status filterGetInfoErrorCode(status_t err);
@@ -226,6 +249,7 @@
// CameraClient functionality
class BasicClient : public virtual RefBase {
+ friend class CameraService;
public:
virtual status_t initialize(sp<CameraProviderManager> manager,
const String8& monitorTags) = 0;
@@ -332,9 +356,18 @@
// - The app-side Binder interface to receive callbacks from us
sp<IBinder> mRemoteBinder; // immutable after constructor
- // permissions management
+ // Permissions management methods for camera lifecycle
+
+ // Notify rest of system/apps about camera opening, and check appops
virtual status_t startCameraOps();
+ // Notify rest of system/apps about camera starting to stream data, and confirm appops
+ virtual status_t startCameraStreamingOps();
+ // Notify rest of system/apps about camera stopping streaming data
+ virtual status_t finishCameraStreamingOps();
+ // Notify rest of system/apps about camera closing
virtual status_t finishCameraOps();
+ // Handle errors for start/checkOps
+ virtual status_t handleAppOpMode(int32_t mode);
std::unique_ptr<AppOpsManager> mAppOpsManager = nullptr;
@@ -349,9 +382,12 @@
}; // class OpsCallback
sp<OpsCallback> mOpsCallback;
- // Track whether startCameraOps was called successfully, to avoid
- // finishing what we didn't start.
+ // Track whether checkOps was called successfully, to avoid
+ // finishing what we didn't start, on camera open.
bool mOpsActive;
+ // Track whether startOps was called successfully on start of
+ // camera streaming.
+ bool mOpsStreaming;
// IAppOpsCallback interface, indirected through opListener
virtual void opChanged(int32_t op, const String16& packageName);
@@ -649,8 +685,7 @@
public virtual IBinder::DeathRecipient {
public:
explicit SensorPrivacyPolicy(wp<CameraService> service)
- : mService(service), mSensorPrivacyEnabled(false), mRegistered(false),
- mHasCameraPrivacyFeature(false), mNeedToCheckCameraPrivacyFeature(true) {}
+ : mService(service), mSensorPrivacyEnabled(false), mRegistered(false) {}
void registerSelf();
void unregisterSelf();
@@ -669,8 +704,6 @@
Mutex mSensorPrivacyLock;
bool mSensorPrivacyEnabled;
bool mRegistered;
- bool mHasCameraPrivacyFeature;
- bool mNeedToCheckCameraPrivacyFeature;
bool hasCameraPrivacyFeature();
};
@@ -928,7 +961,10 @@
mIsVendorListener(isVendorClient),
mOpenCloseCallbackAllowed(openCloseCallbackAllowed) { }
- status_t initialize() {
+ status_t initialize(bool isProcessLocalTest) {
+ if (isProcessLocalTest) {
+ return OK;
+ }
return IInterface::asBinder(mListener)->linkToDeath(this);
}
@@ -1120,6 +1156,46 @@
// Current camera mute mode
bool mOverrideCameraMuteMode = false;
+
+ /**
+ * A listener class that implements the IBinder::DeathRecipient interface
+ * for use to call back the error state injected by the external camera, and
+ * camera service can kill the injection when binder signals process death.
+ */
+ class InjectionStatusListener : public virtual IBinder::DeathRecipient {
+ public:
+ InjectionStatusListener(sp<CameraService> parent) : mParent(parent) {}
+
+ void addListener(const sp<hardware::camera2::ICameraInjectionCallback>& callback);
+ void removeListener();
+ void notifyInjectionError(int errorCode);
+
+ // IBinder::DeathRecipient implementation
+ virtual void binderDied(const wp<IBinder>& who);
+
+ private:
+ Mutex mListenerLock;
+ wp<CameraService> mParent;
+ sp<hardware::camera2::ICameraInjectionCallback> mCameraInjectionCallback;
+ };
+
+ sp<InjectionStatusListener> mInjectionStatusListener;
+
+ /**
+ * A class that implements the hardware::camera2::BnCameraInjectionSession interface
+ */
+ class CameraInjectionSession : public hardware::camera2::BnCameraInjectionSession {
+ public:
+ CameraInjectionSession(sp<CameraService> parent) : mParent(parent) {}
+ virtual ~CameraInjectionSession() {}
+ binder::Status stopInjection() override;
+
+ private:
+ Mutex mInjectionSessionLock;
+ wp<CameraService> mParent;
+ };
+
+ void stopInjectionImpl();
};
} // namespace android
diff --git a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
index 6765c3b..ef15f2d 100644
--- a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
@@ -275,12 +275,17 @@
}
}
+status_t CameraOfflineSessionClient::notifyActive() {
+ return startCameraStreamingOps();
+}
+
void CameraOfflineSessionClient::notifyIdle(
int64_t /*requestCount*/, int64_t /*resultErrorCount*/, bool /*deviceError*/,
const std::vector<hardware::CameraStreamStats>& /*streamStats*/) {
if (mRemoteCallback.get() != nullptr) {
mRemoteCallback->onDeviceIdle();
}
+ finishCameraStreamingOps();
}
void CameraOfflineSessionClient::notifyAutoFocus(uint8_t newState, int triggerId) {
diff --git a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
index ba49325..b219a4c 100644
--- a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
+++ b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
@@ -89,6 +89,7 @@
// NotificationListener API
void notifyError(int32_t errorCode, const CaptureResultExtras& resultExtras) override;
void notifyShutter(const CaptureResultExtras& resultExtras, nsecs_t timestamp) override;
+ status_t notifyActive() override;
void notifyIdle(int64_t requestCount, int64_t resultErrorCount, bool deviceError,
const std::vector<hardware::CameraStreamStats>& streamStats) override;
void notifyAutoFocus(uint8_t newState, int triggerId) override;
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index 1f79354..ce479a1 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -250,10 +250,32 @@
}
template <typename TClientBase>
+status_t Camera2ClientBase<TClientBase>::notifyActive() {
+ if (!mDeviceActive) {
+ status_t res = TClientBase::startCameraStreamingOps();
+ if (res != OK) {
+ ALOGE("%s: Camera %s: Error starting camera streaming ops: %d", __FUNCTION__,
+ TClientBase::mCameraIdStr.string(), res);
+ return res;
+ }
+ CameraServiceProxyWrapper::logActive(TClientBase::mCameraIdStr);
+ }
+ mDeviceActive = true;
+
+ ALOGV("Camera device is now active");
+ return OK;
+}
+
+template <typename TClientBase>
void Camera2ClientBase<TClientBase>::notifyIdle(
int64_t requestCount, int64_t resultErrorCount, bool deviceError,
const std::vector<hardware::CameraStreamStats>& streamStats) {
if (mDeviceActive) {
+ status_t res = TClientBase::finishCameraStreamingOps();
+ if (res != OK) {
+ ALOGE("%s: Camera %s: Error finishing streaming ops: %d", __FUNCTION__,
+ TClientBase::mCameraIdStr.string(), res);
+ }
CameraServiceProxyWrapper::logIdle(TClientBase::mCameraIdStr,
requestCount, resultErrorCount, deviceError, streamStats);
}
@@ -268,11 +290,6 @@
(void)resultExtras;
(void)timestamp;
- if (!mDeviceActive) {
- CameraServiceProxyWrapper::logActive(TClientBase::mCameraIdStr);
- }
- mDeviceActive = true;
-
ALOGV("%s: Shutter notification for request id %" PRId32 " at time %" PRId64,
__FUNCTION__, resultExtras.requestId, timestamp);
}
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.h b/services/camera/libcameraservice/common/Camera2ClientBase.h
index dab0050..b3a38a2 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.h
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.h
@@ -67,6 +67,7 @@
virtual void notifyError(int32_t errorCode,
const CaptureResultExtras& resultExtras);
+ virtual status_t notifyActive(); // Returns errors on app ops permission failures
virtual void notifyIdle(int64_t requestCount, int64_t resultErrorCount,
bool deviceError,
const std::vector<hardware::CameraStreamStats>& streamStats);
diff --git a/services/camera/libcameraservice/common/CameraOfflineSessionBase.h b/services/camera/libcameraservice/common/CameraOfflineSessionBase.h
index e02e146..54e42a6 100644
--- a/services/camera/libcameraservice/common/CameraOfflineSessionBase.h
+++ b/services/camera/libcameraservice/common/CameraOfflineSessionBase.h
@@ -40,10 +40,11 @@
// Required for API 1 and 2
virtual void notifyError(int32_t errorCode,
const CaptureResultExtras &resultExtras) = 0;
-
- // Required only for API2
+ virtual status_t notifyActive() = 0; // May return an error since it checks appops
virtual void notifyIdle(int64_t requestCount, int64_t resultError, bool deviceError,
const std::vector<hardware::CameraStreamStats>& streamStats) = 0;
+
+ // Required only for API2
virtual void notifyShutter(const CaptureResultExtras &resultExtras,
nsecs_t timestamp) = 0;
virtual void notifyPrepared(int streamId) = 0;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index bf7e597..d93b9e5 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -2189,31 +2189,40 @@
std::lock_guard<std::mutex> l(mOutputLock);
listener = mListener.promote();
}
- if (idle && listener != NULL) {
- // Get session stats from the builder, and notify the listener.
- int64_t requestCount, resultErrorCount;
- bool deviceError;
- std::map<int, StreamStats> streamStatsMap;
- mSessionStatsBuilder.buildAndReset(&requestCount, &resultErrorCount,
- &deviceError, &streamStatsMap);
- for (size_t i = 0; i < streamIds.size(); i++) {
- int streamId = streamIds[i];
- auto stats = streamStatsMap.find(streamId);
- if (stats != streamStatsMap.end()) {
- streamStats[i].mRequestCount = stats->second.mRequestedFrameCount;
- streamStats[i].mErrorCount = stats->second.mDroppedFrameCount;
- streamStats[i].mStartLatencyMs = stats->second.mStartLatencyMs;
- streamStats[i].mHistogramType =
- hardware::CameraStreamStats::HISTOGRAM_TYPE_CAPTURE_LATENCY;
- streamStats[i].mHistogramBins.assign(
- stats->second.mCaptureLatencyBins.begin(),
- stats->second.mCaptureLatencyBins.end());
- streamStats[i].mHistogramCounts.assign(
- stats->second.mCaptureLatencyHistogram.begin(),
- stats->second.mCaptureLatencyHistogram.end());
+ status_t res = OK;
+ if (listener != nullptr) {
+ if (idle) {
+ // Get session stats from the builder, and notify the listener.
+ int64_t requestCount, resultErrorCount;
+ bool deviceError;
+ std::map<int, StreamStats> streamStatsMap;
+ mSessionStatsBuilder.buildAndReset(&requestCount, &resultErrorCount,
+ &deviceError, &streamStatsMap);
+ for (size_t i = 0; i < streamIds.size(); i++) {
+ int streamId = streamIds[i];
+ auto stats = streamStatsMap.find(streamId);
+ if (stats != streamStatsMap.end()) {
+ streamStats[i].mRequestCount = stats->second.mRequestedFrameCount;
+ streamStats[i].mErrorCount = stats->second.mDroppedFrameCount;
+ streamStats[i].mStartLatencyMs = stats->second.mStartLatencyMs;
+ streamStats[i].mHistogramType =
+ hardware::CameraStreamStats::HISTOGRAM_TYPE_CAPTURE_LATENCY;
+ streamStats[i].mHistogramBins.assign(
+ stats->second.mCaptureLatencyBins.begin(),
+ stats->second.mCaptureLatencyBins.end());
+ streamStats[i].mHistogramCounts.assign(
+ stats->second.mCaptureLatencyHistogram.begin(),
+ stats->second.mCaptureLatencyHistogram.end());
+ }
}
+ listener->notifyIdle(requestCount, resultErrorCount, deviceError, streamStats);
+ } else {
+ res = listener->notifyActive();
}
- listener->notifyIdle(requestCount, resultErrorCount, deviceError, streamStats);
+ }
+ if (res != OK) {
+ SET_ERR("Camera access permission lost mid-operation: %s (%d)",
+ strerror(-res), res);
}
}
diff --git a/services/camera/libcameraservice/libcameraservice_fuzzer/Android.bp b/services/camera/libcameraservice/libcameraservice_fuzzer/Android.bp
index c7d7c4b..3d74f0b 100644
--- a/services/camera/libcameraservice/libcameraservice_fuzzer/Android.bp
+++ b/services/camera/libcameraservice/libcameraservice_fuzzer/Android.bp
@@ -44,6 +44,7 @@
"libcutils",
"libcameraservice",
"libcamera_client",
+ "liblog",
"libui",
"libgui",
"android.hardware.camera.common@1.0",
diff --git a/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp b/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp
index 54550a5..985b2f8 100644
--- a/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp
+++ b/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp
@@ -18,8 +18,18 @@
* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
*/
+#define LOG_TAG "CameraServiceFuzzer"
+//#define LOG_NDEBUG 0
+
#include <CameraService.h>
+#include <device3/Camera3StreamInterface.h>
+#include <android/hardware/BnCameraServiceListener.h>
+#include <android/hardware/camera2/BnCameraDeviceCallbacks.h>
#include <android/hardware/ICameraServiceListener.h>
+#include <android/hardware/camera2/ICameraDeviceUser.h>
+#include <camera/camera2/OutputConfiguration.h>
+#include <gui/BufferItemConsumer.h>
+#include <gui/IGraphicBufferProducer.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <private/android_filesystem_config.h>
@@ -30,6 +40,7 @@
using namespace std;
const int32_t kPreviewThreshold = 8;
+const int32_t kNumRequestsTested = 8;
const nsecs_t kPreviewTimeout = 5000000000; // .5 [s.]
const nsecs_t kEventTimeout = 10000000000; // 1 [s.]
const size_t kMaxNumLines = USHRT_MAX;
@@ -39,6 +50,23 @@
hardware::ICameraService::CAMERA_TYPE_ALL};
const int kCameraApiVersion[] = {android::CameraService::API_VERSION_1,
android::CameraService::API_VERSION_2};
+const uint8_t kSensorPixelModes[] = {ANDROID_SENSOR_PIXEL_MODE_DEFAULT,
+ ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION};
+const int32_t kRequestTemplates[] = {
+ hardware::camera2::ICameraDeviceUser::TEMPLATE_PREVIEW,
+ hardware::camera2::ICameraDeviceUser::TEMPLATE_STILL_CAPTURE,
+ hardware::camera2::ICameraDeviceUser::TEMPLATE_RECORD,
+ hardware::camera2::ICameraDeviceUser::TEMPLATE_VIDEO_SNAPSHOT,
+ hardware::camera2::ICameraDeviceUser::TEMPLATE_MANUAL,
+ hardware::camera2::ICameraDeviceUser::TEMPLATE_ZERO_SHUTTER_LAG
+};
+
+const int32_t kRotations[] = {
+ camera3::CAMERA_STREAM_ROTATION_0,
+ camera3::CAMERA_STREAM_ROTATION_90,
+ camera3::CAMERA_STREAM_ROTATION_270
+};
+
const int kLayerMetadata[] = {
0x00100000 /*GRALLOC_USAGE_RENDERSCRIPT*/, 0x00000003 /*GRALLOC_USAGE_SW_READ_OFTEN*/,
0x00000100 /*GRALLOC_USAGE_HW_TEXTURE*/, 0x00000800 /*GRALLOC_USAGE_HW_COMPOSER*/,
@@ -69,15 +97,15 @@
class CameraFuzzer : public ::android::hardware::BnCameraClient {
public:
- CameraFuzzer() = default;
+ CameraFuzzer(sp<CameraService> cs, std::shared_ptr<FuzzedDataProvider> fp) :
+ mCameraService(cs), mFuzzedDataProvider(fp) {};
~CameraFuzzer() { deInit(); }
- bool init();
- void process(const uint8_t *data, size_t size);
+ void process();
void deInit();
private:
- FuzzedDataProvider *mFuzzedDataProvider = nullptr;
sp<CameraService> mCameraService = nullptr;
+ std::shared_ptr<FuzzedDataProvider> mFuzzedDataProvider = nullptr;
sp<SurfaceComposerClient> mComposerClient = nullptr;
int32_t mNumCameras = 0;
size_t mPreviewBufferCount = 0;
@@ -167,19 +195,7 @@
return rc;
}
-bool CameraFuzzer::init() {
- setuid(AID_MEDIA);
- mCameraService = new CameraService();
- if (mCameraService) {
- return true;
- }
- return false;
-}
-
void CameraFuzzer::deInit() {
- if (mCameraService) {
- mCameraService = nullptr;
- }
if (mComposerClient) {
mComposerClient->dispose();
}
@@ -298,12 +314,12 @@
for (int32_t cameraId = 0; cameraId < mNumCameras; ++cameraId) {
getCameraInformation(cameraId);
- const String16 opPackageName("com.fuzzer.poc");
::android::binder::Status rc;
sp<ICamera> cameraDevice;
- rc = mCameraService->connect(this, cameraId, opPackageName, AID_MEDIA, AID_ROOT,
- &cameraDevice);
+ rc = mCameraService->connect(this, cameraId, String16(),
+ android::CameraService::USE_CALLING_UID, android::CameraService::USE_CALLING_PID,
+ &cameraDevice);
if (!rc.isOk()) {
// camera not connected
return;
@@ -405,8 +421,7 @@
}
}
-void CameraFuzzer::process(const uint8_t *data, size_t size) {
- mFuzzedDataProvider = new FuzzedDataProvider(data, size);
+void CameraFuzzer::process() {
getNumCameras();
invokeCameraSound();
if (mNumCameras > 0) {
@@ -415,19 +430,169 @@
invokeDump();
invokeShellCommand();
invokeNotifyCalls();
- delete mFuzzedDataProvider;
+}
+
+class TestCameraServiceListener : public hardware::BnCameraServiceListener {
+public:
+ virtual ~TestCameraServiceListener() {};
+
+ virtual binder::Status onStatusChanged(int32_t , const String16&) {
+ return binder::Status::ok();
+ };
+
+ virtual binder::Status onPhysicalCameraStatusChanged(int32_t /*status*/,
+ const String16& /*cameraId*/, const String16& /*physicalCameraId*/) {
+ // No op
+ return binder::Status::ok();
+ };
+
+ virtual binder::Status onTorchStatusChanged(int32_t /*status*/, const String16& /*cameraId*/) {
+ return binder::Status::ok();
+ };
+
+ virtual binder::Status onCameraAccessPrioritiesChanged() {
+ // No op
+ return binder::Status::ok();
+ }
+
+ virtual binder::Status onCameraOpened(const String16& /*cameraId*/,
+ const String16& /*clientPackageName*/) {
+ // No op
+ return binder::Status::ok();
+ }
+
+ virtual binder::Status onCameraClosed(const String16& /*cameraId*/) {
+ // No op
+ return binder::Status::ok();
+ }
+};
+
+class TestCameraDeviceCallbacks : public hardware::camera2::BnCameraDeviceCallbacks {
+public:
+ TestCameraDeviceCallbacks() {}
+
+ virtual ~TestCameraDeviceCallbacks() {}
+
+ virtual binder::Status onDeviceError(int /*errorCode*/,
+ const CaptureResultExtras& /*resultExtras*/) {
+ return binder::Status::ok();
+ }
+
+ virtual binder::Status onDeviceIdle() {
+ return binder::Status::ok();
+ }
+
+ virtual binder::Status onCaptureStarted(const CaptureResultExtras& /*resultExtras*/,
+ int64_t /*timestamp*/) {
+ return binder::Status::ok();
+ }
+
+ virtual binder::Status onResultReceived(const CameraMetadata& /*metadata*/,
+ const CaptureResultExtras& /*resultExtras*/,
+ const std::vector<PhysicalCaptureResultInfo>& /*physicalResultInfos*/) {
+ return binder::Status::ok();
+ }
+
+ virtual binder::Status onPrepared(int /*streamId*/) {
+ return binder::Status::ok();
+ }
+
+ virtual binder::Status onRepeatingRequestError(
+ int64_t /*lastFrameNumber*/, int32_t /*stoppedSequenceId*/) {
+ return binder::Status::ok();
+ }
+
+ virtual binder::Status onRequestQueueEmpty() {
+ return binder::Status::ok();
+ }
+};
+
+class Camera2Fuzzer {
+ public:
+ Camera2Fuzzer(sp<CameraService> cs, std::shared_ptr<FuzzedDataProvider> fp) :
+ mCameraService(cs), mFuzzedDataProvider(fp) { };
+ ~Camera2Fuzzer() {}
+ void process();
+ private:
+ sp<CameraService> mCameraService = nullptr;
+ std::shared_ptr<FuzzedDataProvider> mFuzzedDataProvider = nullptr;
+};
+
+void Camera2Fuzzer::process() {
+ sp<TestCameraServiceListener> listener = new TestCameraServiceListener();
+ std::vector<hardware::CameraStatus> statuses;
+ mCameraService->addListenerTest(listener, &statuses);
+ for (auto s : statuses) {
+ sp<TestCameraDeviceCallbacks> callbacks(new TestCameraDeviceCallbacks());
+ sp<hardware::camera2::ICameraDeviceUser> device;
+ mCameraService->connectDevice(callbacks, String16(s.cameraId), String16(), {},
+ android::CameraService::USE_CALLING_UID, &device);
+ if (device == nullptr) {
+ continue;
+ }
+ device->beginConfigure();
+ sp<IGraphicBufferProducer> gbProducer;
+ sp<IGraphicBufferConsumer> gbConsumer;
+ BufferQueue::createBufferQueue(&gbProducer, &gbConsumer);
+ sp<BufferItemConsumer> opaqueConsumer = new BufferItemConsumer(gbConsumer,
+ GRALLOC_USAGE_SW_READ_NEVER, /*maxImages*/8, /*controlledByApp*/true);
+ opaqueConsumer->setName(String8("Roger"));
+
+ // Set to VGA dimension for default, as that is guaranteed to be present
+ gbConsumer->setDefaultBufferSize(640, 480);
+ gbConsumer->setDefaultBufferFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED);
+
+ sp<Surface> surface(new Surface(gbProducer, /*controlledByApp*/false));
+
+ String16 noPhysicalId;
+ size_t rotations = sizeof(kRotations) / sizeof(int32_t) - 1;
+ OutputConfiguration output(gbProducer,
+ kRotations[mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(0, rotations)],
+ noPhysicalId);
+ int streamId;
+ device->createStream(output, &streamId);
+ CameraMetadata sessionParams;
+ std::vector<int> offlineStreamIds;
+ device->endConfigure(/*isConstrainedHighSpeed*/ mFuzzedDataProvider->ConsumeBool(),
+ sessionParams, ns2ms(systemTime()), &offlineStreamIds);
+
+ CameraMetadata requestTemplate;
+ size_t requestTemplatesSize = sizeof(kRequestTemplates) /sizeof(int32_t) - 1;
+ device->createDefaultRequest(kRequestTemplates[
+ mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(0, requestTemplatesSize)],
+ /*out*/&requestTemplate);
+ hardware::camera2::CaptureRequest request;
+ request.mSurfaceList.add(surface);
+ request.mIsReprocess = false;
+ hardware::camera2::utils::SubmitInfo info;
+ for (int i = 0; i < kNumRequestsTested; i++) {
+ uint8_t sensorPixelMode =
+ kSensorPixelModes[mFuzzedDataProvider->ConsumeBool() ? 1 : 0];
+ requestTemplate.update(ANDROID_SENSOR_PIXEL_MODE, &sensorPixelMode, 1);
+ request.mPhysicalCameraSettings.clear();
+ request.mPhysicalCameraSettings.push_back({s.cameraId.string(), requestTemplate});
+ device->submitRequest(request, /*streaming*/false, /*out*/&info);
+ ALOGV("%s : camera id %s submit request id %d",__FUNCTION__, s.cameraId.string(),
+ info.mRequestId);
+ }
+ device->disconnect();
+ }
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
if (size < 1) {
return 0;
}
- sp<CameraFuzzer> camerafuzzer = new CameraFuzzer();
+ setuid(AID_CAMERASERVER);
+ std::shared_ptr<FuzzedDataProvider> fp = std::make_shared<FuzzedDataProvider>(data, size);
+ sp<CameraService> cs = new CameraService();
+ cs->clearCachedVariables();
+ sp<CameraFuzzer> camerafuzzer = new CameraFuzzer(cs, fp);
if (!camerafuzzer) {
return 0;
}
- if (camerafuzzer->init()) {
- camerafuzzer->process(data, size);
- }
+ camerafuzzer->process();
+ Camera2Fuzzer camera2fuzzer(cs, fp);
+ camera2fuzzer.process();
return 0;
}
diff --git a/services/mediametrics/MediaMetricsService.cpp b/services/mediametrics/MediaMetricsService.cpp
index 5e672ee..1d64878 100644
--- a/services/mediametrics/MediaMetricsService.cpp
+++ b/services/mediametrics/MediaMetricsService.cpp
@@ -545,12 +545,13 @@
return AStatsManager_PULL_SKIP;
}
std::lock_guard _l(mLock);
+ bool dumped = false;
for (auto &item : mPullableItems[key]) {
if (const auto sitem = item.lock()) {
- dump2Statsd(sitem, data, mStatsdLog);
+ dumped |= dump2Statsd(sitem, data, mStatsdLog);
}
}
mPullableItems[key].clear();
- return AStatsManager_PULL_SUCCESS;
+ return dumped ? AStatsManager_PULL_SUCCESS : AStatsManager_PULL_SKIP;
}
} // namespace android
diff --git a/services/mediametrics/statsd_codec.cpp b/services/mediametrics/statsd_codec.cpp
index 8a2158f..4539ad5 100644
--- a/services/mediametrics/statsd_codec.cpp
+++ b/services/mediametrics/statsd_codec.cpp
@@ -33,7 +33,7 @@
#include "cleaner.h"
#include "MediaMetricsService.h"
-#include "frameworks/proto_logging/stats/enums/stats/mediametrics/mediametrics.pb.h"
+#include "frameworks/proto_logging/stats/message/mediametrics_message.pb.h"
#include "iface_statsd.h"
namespace android {
@@ -51,7 +51,7 @@
// the rest into our own proto
//
- ::android::stats::mediametrics::CodecData metrics_proto;
+ ::android::stats::mediametrics_message::CodecData metrics_proto;
// flesh out the protobuf we'll hand off with our data
//
@@ -95,7 +95,7 @@
if ( item->getInt32("android.media.mediacodec.rotation-degrees", &rotation)) {
metrics_proto.set_rotation(rotation);
}
- // android.media.mediacodec.crypto int32 (although missing if not needed
+ // android.media.mediacodec.crypto int32 (although missing if not needed)
int32_t crypto = -1;
if ( item->getInt32("android.media.mediacodec.crypto", &crypto)) {
metrics_proto.set_crypto(crypto);
@@ -185,15 +185,114 @@
metrics_proto.set_lifetime_millis(lifetime_millis);
}
- // new for S; need to plumb through to westworld
- // android.media.mediacodec.channelCount int32
- // android.media.mediacodec.sampleRate int32
+ // android.media.mediacodec.channelCount
+ int32_t channelCount = -1;
+ if ( item->getInt32("android.media.mediacodec.channelCount", &channelCount)) {
+ metrics_proto.set_channel_count(channelCount);
+ }
- // new for S; need to plumb through to westworld
+ // android.media.mediacodec.sampleRate
+ int32_t sampleRate = -1;
+ if ( item->getInt32("android.media.mediacodec.sampleRate", &sampleRate)) {
+ metrics_proto.set_sample_rate(sampleRate);
+ }
+
// TODO PWG may want these fuzzed up a bit to obscure some precision
- // android.media.mediacodec.vencode.bytes int64
- // android.media.mediacodec.vencode.frames int64
- // android.media.mediacodec.vencode.durationUs int64
+ // android.media.mediacodec.vencode.bytes
+ int64_t bytes = -1;
+ if ( item->getInt64("android.media.mediacodec.vencode.bytes", &bytes)) {
+ metrics_proto.set_video_encode_bytes(bytes);
+ }
+
+ // android.media.mediacodec.vencode.frames
+ int64_t frames = -1;
+ if ( item->getInt64("android.media.mediacodec.vencode.frames", &frames)) {
+ metrics_proto.set_video_encode_frames(frames);
+ }
+
+ // android.media.mediacodec.vencode.durationUs
+ int64_t durationUs = -1;
+ if ( item->getInt64("android.media.mediacodec.vencode.durationUs", &durationUs)) {
+ metrics_proto.set_video_encode_duration_us(durationUs);
+ }
+
+ // android.media.mediacodec.color-format
+ int32_t colorFormat = -1;
+ if ( item->getInt32("android.media.mediacodec.color-format", &colorFormat)) {
+ metrics_proto.set_color_format(colorFormat);
+ }
+
+ // android.media.mediacodec.frame-rate
+ double frameRate = -1.0;
+ if ( item->getDouble("android.media.mediacodec.frame-rate", &frameRate)) {
+ metrics_proto.set_frame_rate(frameRate);
+ }
+
+ // android.media.mediacodec.capture-rate
+ double captureRate = -1.0;
+ if ( item->getDouble("android.media.mediacodec.capture-rate", &captureRate)) {
+ metrics_proto.set_capture_rate(captureRate);
+ }
+
+ // android.media.mediacodec.operating-rate
+ double operatingRate = -1.0;
+ if ( item->getDouble("android.media.mediacodec.operating-rate", &operatingRate)) {
+ metrics_proto.set_operating_rate(operatingRate);
+ }
+
+ // android.media.mediacodec.priority
+ int32_t priority = -1;
+ if ( item->getInt32("android.media.mediacodec.priority", &priority)) {
+ metrics_proto.set_priority(priority);
+ }
+
+ // android.media.mediacodec.video-qp-i-min
+ int32_t qpIMin = -1;
+ if ( item->getInt32("android.media.mediacodec.video-qp-i-min", &qpIMin)) {
+ metrics_proto.set_video_qp_i_min(qpIMin);
+ }
+
+ // android.media.mediacodec.video-qp-i-max
+ int32_t qpIMax = -1;
+ if ( item->getInt32("android.media.mediacodec.video-qp-i-max", &qpIMax)) {
+ metrics_proto.set_video_qp_i_max(qpIMax);
+ }
+
+ // android.media.mediacodec.video-qp-p-min
+ int32_t qpPMin = -1;
+ if ( item->getInt32("android.media.mediacodec.video-qp-p-min", &qpPMin)) {
+ metrics_proto.set_video_qp_p_min(qpPMin);
+ }
+
+ // android.media.mediacodec.video-qp-p-max
+ int32_t qpPMax = -1;
+ if ( item->getInt32("android.media.mediacodec.video-qp-p-max", &qpPMax)) {
+ metrics_proto.set_video_qp_p_max(qpPMax);
+ }
+
+ // android.media.mediacodec.video-qp-b-min
+ int32_t qpBMin = -1;
+ if ( item->getInt32("android.media.mediacodec.video-qp-b-min", &qpBMin)) {
+ metrics_proto.set_video_qp_b_min(qpIMin);
+ }
+
+ // android.media.mediacodec.video-qp-b-max
+ int32_t qpBMax = -1;
+ if ( item->getInt32("android.media.mediacodec.video-qp-b-max", &qpBMax)) {
+ metrics_proto.set_video_qp_b_max(qpBMax);
+ }
+
+ // android.media.mediacodec.video.input.bytes
+ int64_t inputBytes = -1;
+ if ( item->getInt64("android.media.mediacodec.video.input.bytes", &inputBytes)) {
+ metrics_proto.set_video_input_bytes(inputBytes);
+ }
+
+ // android.media.mediacodec.video.input.frames
+ int64_t inputFrames = -1;
+ if ( item->getInt64("android.media.mediacodec.video.input.frames", &inputFrames)) {
+ metrics_proto.set_video_input_frames(inputFrames);
+ }
std::string serialized;
if (!metrics_proto.SerializeToString(&serialized)) {
diff --git a/services/mediametrics/statsd_drm.cpp b/services/mediametrics/statsd_drm.cpp
index 27fd089..287fb8d 100644
--- a/services/mediametrics/statsd_drm.cpp
+++ b/services/mediametrics/statsd_drm.cpp
@@ -59,9 +59,16 @@
std::string description;
(void) item->getString("description", &description);
+ std::string serialized_metrics;
+ (void) item->getString("serialized_metrics", &serialized_metrics);
+ if (serialized_metrics.empty()) {
+ ALOGD("statsd_mediadrm skipping empty entry");
+ return false;
+ }
+
// This field is left here for backward compatibility.
// This field is not used anymore.
- const std::string kUnusedField("unused");
+ const std::string kUnusedField("");
android::util::BytesField bf_serialized(kUnusedField.c_str(), kUnusedField.size());
int result = android::util::stats_write(android::util::MEDIAMETRICS_MEDIADRM_REPORTED,
timestamp_nanos, package_name.c_str(), package_version_code,
@@ -188,6 +195,11 @@
(void) item->getString("plugin_metrics", &plugin_metrics);
const auto plugin_raw(base64DecodeNoPad(plugin_metrics));
+ if (serialized_metrics.size() == 0 && plugin_metrics.size() == 0) {
+ ALOGD("statsd_mediadrm_puller skipping empty entry");
+ return false;
+ }
+
std::string vendor;
(void) item->getString("vendor", &vendor);
std::string description;
diff --git a/services/mediametrics/statsd_mediaparser.cpp b/services/mediametrics/statsd_mediaparser.cpp
index f543425..6cceb06 100644
--- a/services/mediametrics/statsd_mediaparser.cpp
+++ b/services/mediametrics/statsd_mediaparser.cpp
@@ -79,6 +79,9 @@
int32_t videoHeight = -1;
item->getInt32("android.media.mediaparser.videoHeight", &videoHeight);
+ std::string logSessionId;
+ item->getString("android.media.mediaparser.logSessionId", &logSessionId);
+
if (enabled_statsd) {
(void) android::util::stats_write(android::util::MEDIAMETRICS_MEDIAPARSER_REPORTED,
timestamp_nanos,
@@ -94,11 +97,11 @@
trackCodecs.c_str(),
alteredParameters.c_str(),
videoWidth,
- videoHeight);
+ videoHeight,
+ logSessionId.c_str());
} else {
ALOGV("NOT sending MediaParser media metrics.");
}
- // TODO: Cleanup after playback_id is merged.
std::stringstream log;
log << "result:" << "(result)" << " {"
<< " mediametrics_mediaparser_reported:"
@@ -117,8 +120,7 @@
<< " altered_parameters:" << alteredParameters
<< " video_width:" << videoWidth
<< " video_height:" << videoHeight
- // TODO: Add MediaParser playback_id
- // << " playback_id:" << playbackId
+ << " log_session_id:" << logSessionId
<< " }";
statsdLog->log(android::util::MEDIAMETRICS_MEDIAPARSER_REPORTED, log.str());
return true;
diff --git a/services/mediatranscoding/MediaTranscodingService.cpp b/services/mediatranscoding/MediaTranscodingService.cpp
index 8b64134..b80fe57 100644
--- a/services/mediatranscoding/MediaTranscodingService.cpp
+++ b/services/mediatranscoding/MediaTranscodingService.cpp
@@ -131,10 +131,10 @@
void MediaTranscodingService::instantiate() {
std::shared_ptr<MediaTranscodingService> service =
::ndk::SharedRefBase::make<MediaTranscodingService>();
- binder_status_t status =
- AServiceManager_addService(service->asBinder().get(), getServiceName());
- if (status != STATUS_OK) {
- return;
+ if (__builtin_available(android __TRANSCODING_MIN_API__, *)) {
+ // Once service is started, we want it to stay even is client side perished.
+ AServiceManager_forceLazyServicesPersist(true /*persist*/);
+ (void)AServiceManager_registerLazyService(service->asBinder().get(), getServiceName());
}
}
diff --git a/services/mediatranscoding/tests/MediaTranscodingServiceTestHelper.h b/services/mediatranscoding/tests/MediaTranscodingServiceTestHelper.h
index 20e4bfb..0cb2fad 100644
--- a/services/mediatranscoding/tests/MediaTranscodingServiceTestHelper.h
+++ b/services/mediatranscoding/tests/MediaTranscodingServiceTestHelper.h
@@ -481,7 +481,7 @@
// Need thread pool to receive callbacks, otherwise oneway callbacks are
// silently ignored.
ABinderProcess_startThreadPool();
- ::ndk::SpAIBinder binder(AServiceManager_getService("media.transcoding"));
+ ::ndk::SpAIBinder binder(AServiceManager_waitForService("media.transcoding"));
mService = IMediaTranscodingService::fromBinder(binder);
if (mService == nullptr) {
ALOGE("Failed to connect to the media.trascoding service.");
diff --git a/services/tuner/TunerDescrambler.cpp b/services/tuner/TunerDescrambler.cpp
index bdf826c..b7ae167 100644
--- a/services/tuner/TunerDescrambler.cpp
+++ b/services/tuner/TunerDescrambler.cpp
@@ -111,11 +111,11 @@
DemuxPid hidlPid;
switch (pid.getTag()) {
case TunerDemuxPid::tPid: {
- hidlPid.tPid((uint16_t)pid.tPid);
+ hidlPid.tPid((uint16_t)pid.get<TunerDemuxPid::tPid>());
break;
}
case TunerDemuxPid::mmtpPid: {
- hidlPid.mmtpPid((uint16_t)pid.mmtpPid);
+ hidlPid.mmtpPid((uint16_t)pid.get<TunerDemuxPid::mmtpPid>());
break;
}
}
diff --git a/services/tuner/TunerFilter.cpp b/services/tuner/TunerFilter.cpp
index e957b83..039fd31 100644
--- a/services/tuner/TunerFilter.cpp
+++ b/services/tuner/TunerFilter.cpp
@@ -685,7 +685,7 @@
DemuxFilterMediaEvent mediaEvent = e.media();
TunerFilterMediaEvent tunerMedia;
- tunerMedia.streamId = static_cast<int>(mediaEvent.streamId);
+ tunerMedia.streamId = static_cast<char16_t>(mediaEvent.streamId);
tunerMedia.isPtsPresent = mediaEvent.isPtsPresent;
tunerMedia.pts = static_cast<long>(mediaEvent.pts);
tunerMedia.dataLength = static_cast<int>(mediaEvent.dataLength);
@@ -732,10 +732,10 @@
DemuxFilterSectionEvent sectionEvent = e.section();
TunerFilterSectionEvent tunerSection;
- tunerSection.tableId = static_cast<char>(sectionEvent.tableId);
- tunerSection.version = static_cast<char>(sectionEvent.version);
- tunerSection.sectionNum = static_cast<char>(sectionEvent.sectionNum);
- tunerSection.dataLength = static_cast<char>(sectionEvent.dataLength);
+ tunerSection.tableId = static_cast<char16_t>(sectionEvent.tableId);
+ tunerSection.version = static_cast<char16_t>(sectionEvent.version);
+ tunerSection.sectionNum = static_cast<char16_t>(sectionEvent.sectionNum);
+ tunerSection.dataLength = static_cast<char16_t>(sectionEvent.dataLength);
TunerFilterEvent tunerEvent;
tunerEvent.set<TunerFilterEvent::section>(move(tunerSection));
@@ -749,8 +749,8 @@
DemuxFilterPesEvent pesEvent = e.pes();
TunerFilterPesEvent tunerPes;
- tunerPes.streamId = static_cast<char>(pesEvent.streamId);
- tunerPes.dataLength = static_cast<int>(pesEvent.dataLength);
+ tunerPes.streamId = static_cast<char16_t>(pesEvent.streamId);
+ tunerPes.dataLength = static_cast<char16_t>(pesEvent.dataLength);
tunerPes.mpuSequenceNumber = static_cast<int>(pesEvent.mpuSequenceNumber);
TunerFilterEvent tunerEvent;
@@ -777,9 +777,9 @@
}
if (tsRecordEvent.pid.getDiscriminator() == DemuxPid::hidl_discriminator::tPid) {
- tunerTsRecord.pid = static_cast<char>(tsRecordEvent.pid.tPid());
+ tunerTsRecord.pid = static_cast<char16_t>(tsRecordEvent.pid.tPid());
} else {
- tunerTsRecord.pid = static_cast<char>(Constant::INVALID_TS_PID);
+ tunerTsRecord.pid = static_cast<char16_t>(Constant::INVALID_TS_PID);
}
tunerTsRecord.scIndexMask = scIndexMask;
@@ -839,7 +839,7 @@
tunerDownload.itemFragmentIndex = static_cast<int>(downloadEvent.itemFragmentIndex);
tunerDownload.mpuSequenceNumber = static_cast<int>(downloadEvent.mpuSequenceNumber);
tunerDownload.lastItemFragmentIndex = static_cast<int>(downloadEvent.lastItemFragmentIndex);
- tunerDownload.dataLength = static_cast<char>(downloadEvent.dataLength);
+ tunerDownload.dataLength = static_cast<char16_t>(downloadEvent.dataLength);
TunerFilterEvent tunerEvent;
tunerEvent.set<TunerFilterEvent::download>(move(tunerDownload));
@@ -853,7 +853,7 @@
DemuxFilterIpPayloadEvent ipPayloadEvent = e.ipPayload();
TunerFilterIpPayloadEvent tunerIpPayload;
- tunerIpPayload.dataLength = static_cast<char>(ipPayloadEvent.dataLength);
+ tunerIpPayload.dataLength = static_cast<char16_t>(ipPayloadEvent.dataLength);
TunerFilterEvent tunerEvent;
tunerEvent.set<TunerFilterEvent::ipPayload>(move(tunerIpPayload));
diff --git a/services/tuner/aidl/android/media/tv/tuner/TunerDemuxPid.aidl b/services/tuner/aidl/android/media/tv/tuner/TunerDemuxPid.aidl
index 51c6378..8b238b6 100644
--- a/services/tuner/aidl/android/media/tv/tuner/TunerDemuxPid.aidl
+++ b/services/tuner/aidl/android/media/tv/tuner/TunerDemuxPid.aidl
@@ -22,7 +22,7 @@
* {@hide}
*/
union TunerDemuxPid {
- int tPid;
+ char tPid;
- int mmtpPid;
+ char mmtpPid;
}
diff --git a/services/tuner/aidl/android/media/tv/tuner/TunerFilterMediaEvent.aidl b/services/tuner/aidl/android/media/tv/tuner/TunerFilterMediaEvent.aidl
index 5842c0d..c3dbce9 100644
--- a/services/tuner/aidl/android/media/tv/tuner/TunerFilterMediaEvent.aidl
+++ b/services/tuner/aidl/android/media/tv/tuner/TunerFilterMediaEvent.aidl
@@ -25,7 +25,7 @@
* {@hide}
*/
parcelable TunerFilterMediaEvent {
- int streamId;
+ char streamId;
/**
* true if PTS is present in PES header.
diff --git a/services/tuner/aidl/android/media/tv/tuner/TunerFilterPesEvent.aidl b/services/tuner/aidl/android/media/tv/tuner/TunerFilterPesEvent.aidl
index f7ee286..dc1ecc6 100644
--- a/services/tuner/aidl/android/media/tv/tuner/TunerFilterPesEvent.aidl
+++ b/services/tuner/aidl/android/media/tv/tuner/TunerFilterPesEvent.aidl
@@ -27,7 +27,7 @@
/**
* Data size in bytes of PES data
*/
- int dataLength;
+ char dataLength;
/**
* MPU sequence number of filtered data
diff --git a/services/tuner/aidl/android/media/tv/tuner/TunerFrontendIsdbs3Settings.aidl b/services/tuner/aidl/android/media/tv/tuner/TunerFrontendIsdbs3Settings.aidl
index 0923868..9a11fd5 100644
--- a/services/tuner/aidl/android/media/tv/tuner/TunerFrontendIsdbs3Settings.aidl
+++ b/services/tuner/aidl/android/media/tv/tuner/TunerFrontendIsdbs3Settings.aidl
@@ -27,7 +27,7 @@
*/
int frequency;
- int streamId;
+ char streamId;
int streamIdType;
diff --git a/services/tuner/aidl/android/media/tv/tuner/TunerFrontendIsdbsSettings.aidl b/services/tuner/aidl/android/media/tv/tuner/TunerFrontendIsdbsSettings.aidl
index 2ae9092..dff9f4a 100644
--- a/services/tuner/aidl/android/media/tv/tuner/TunerFrontendIsdbsSettings.aidl
+++ b/services/tuner/aidl/android/media/tv/tuner/TunerFrontendIsdbsSettings.aidl
@@ -27,7 +27,7 @@
*/
int frequency;
- int streamId;
+ char streamId;
int streamIdType;